From ab1e343fcde49956f6eef5b7dc829916dfb12f05 Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Tue, 9 Jun 2020 20:25:41 -0700 Subject: [PATCH] Add files via upload --- ipynb/How To Count Things.ipynb | 4334 ++++++++++++++++++++++--------- 1 file changed, 3152 insertions(+), 1182 deletions(-) diff --git a/ipynb/How To Count Things.ipynb b/ipynb/How To Count Things.ipynb index e29cbbe..bb4847b 100644 --- a/ipynb/How To Count Things.ipynb +++ b/ipynb/How To Count Things.ipynb @@ -4,116 +4,123 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
Peter Norvig, Updated Sept 2018
\n", + "
Peter Norvig
Updated Sep 2018, May 2020
\n", "\n", "![the count](https://vignette.wikia.nocookie.net/muppet/images/9/90/CountCountsLP%282%29.jpg/revision/latest/scale-to-width-down/280?cb=20140628202329)\n", "\n", "# How to Count Things\n", "\n", - "Sesame Street teaches us to easily count up to ten using our fingers. A computer doesn't have fingers, but it too can use brute force, enumerating things one by one, to easily count up to a billion or so.\n", + "Sesame Street teaches us to count up to ten using our fingers. A computer doesn't have fingers, but it too can use brute force, enumerating things one by one, to easily count up to a billion or so. So in that sense, a billion is a small number. It is rare to get more than a billion things together in one place, but it is common to encounter situations where there many billions of combinations of things; indeed many problems have more combinations of things than the number of atoms in the Universe. \n", "\n", + "Thus, for really big numbers we need a portfolio of counting strategies. Here is a partial list:\n", "\n", + "- **Brute Force enumeration**: Generate all the things, and count them one by one.
*Example*: How many odd numbers from 1 to 10? Answer: Generate {1, 3, 5, 7, 9}, count 5.\n", + "- **Enumerate and test**: Generate a larger set of candidate things, and count the ones that satisfy some criteria.
*Example*: How many odd prime numbers from 1 to 10? Answer: Generate {1, 3, 5, 7, 9}, test each one for primality, count 3.\n", + "- **Incremental enumeration**: When the things we are counting have parts, don't generate all possible complete things and then check each one to see if it is valid. Instead, generate the first part of a thing, and check if that part is valid so far. If it is, generate all the possibilities for the next part, but if it is not, stop there. That means that many invalid things will never get generated, saving time.
*Example*: Given a set of *n* cities, how many acyclic paths through some subset of cities are in alphabetical order by city name? Brute force enumeration would generate all permutations up to length *n* and check if each one was alphabetical; incremental enumeration would start generating paths and only extend them with cities in the correct order.\n", + "- **Abstract enumeration**: put the things into equivalence classes, and calculate how many there are in each class. Then we don't have to enumerate all the things; we can consider many at the same time.\n", + "- **Divide and conquer**: Split the problem into parts, solve each part, and combine the results.
*Example*: How many ways are there of getting a straight flush in poker? We can divide the problem into 4 subproblems, one for each suit. Then for each suit we can say: a straight can have one of 10 different high cards (5 through Ace), so there are 10 possible straights for each suit. The total number of straight flushes is 40, which you can think of either as multiplying 4 and 10, the numbers from the two independent components of the problem, or you can think of as adding 10+10+10+10 for the four disjoint parts of the problem.\n", + "- **Recursive divide and conquer**: often we break a problem down into smaller pieces that are recursive instances of the same type of problem. We conquer by solving the smaller pieces and combining results.
*Example*: How many permutations are there of *n* things? If *n* > 0, solve by finding the number of permutations of *n* - 1 things, and multiplying by *n*.\n", + "- **Formula calculation**: Use mathematical thinking to derive a formula for the number of things.
*Example*: How many odd numbers from 1 to *n*? The formula is ⌈n/2⌉, meaning \"divide *n* by 2 and round up\".\n", + "- **Remembering**: Sometimes there are multiple ways to break a problem into subproblems, and when solving the big problem we may come across the same subproblem more than once. We can remember the solution to the subproblem so that we don't recompute it multiple times. We call that *memoizing* or *caching* the results; we can use the decorator `@lru_cache`.\n", + "- **Simulation**: Sometimes it is difficult to exactly count all the things. But you can do a random simulation in which you record the things that randomly come up, and use those results as an estimate.\n", + "- **Visualization**: When you're stuck, making a chart or table or plot of examples can help you see patterns that can lead to solutions.\n", + "- **Checking**: make sure that your calculations work for small test cases that you verify by hand. Create two different programs and check that they agree with each other. A common approach is to have one straightforward but inefficient program that is easy to see is correct, and one program that is optimized for speed but more complex. If the two programs agree on the small inputs, you can have more confidence they are both correct.)\n", + "- **Standing on shoulders**: it is fun to solve a problem on your own, but sometimes the right approach is to look up how others have solved it before. Sometimes you need to do some work to understand the problem better before you know how to search for a prior solution.
*Example*: In how many ways can a convex polygon be cut into triangles by connecting vertices? You could type the question directly as [a search](https://www.google.com/search?q=In+how+many+ways+can+a+convex+polygon+be+cut+into+triangles+by+connecting+vertices) and find some helpful answers. You could also solve the problem for small polygons (with *n* = 3 to 7 sides), note that the sequence of answers is [\"1, 2, 5, 14, 42\"](https://www.google.com/search?q=%221%2C+2%2C+5%2C+14%2C+42%22&oq=%221%2C+2%2C+5%2C+14%2C+42%22) and see that a search reveals that these are called [Catalan Numbers](https://en.wikipedia.org/wiki/Catalan_number) and that there is a lot written about them.
*Example*: A coach wants to create a basketball lineup of three shooters and two rebounders. She has seven shooters and five rebounders to select from. How many different lineups can she make? Entering the text of the whole problem as a search query gives [results about basketball](https://www.google.com/search?q=A+coach+wants+to+create+a+basketball+lineup+of+three+shooters+and+two+rebounders.+She+has+seven+shooters+and+five+rebounders+to+select+from.+How+many+different+lineups+can+she+make%3F&oq=A+coach+wants+to+create+a+basketball+lineup+of+three+shooters+and+two+rebounders.+She+has+seven+shooters+and+five+rebounders+to+select+from.+How+many+different+lineups+can+she+make), not about combinatorics. You need to understand the problem and standard terminology well enough to realize that a better query is [7 choose 3 * 5 choose 2](https://www.google.com/search?q=7+choose+3+*+5+choose+2).\n", "\n", - "So in that sense, a billion is a small number. For really big numbers, like 10100, we need a better strategy: counting by **calculating** the number of things rather than **enumerating** them. This notebook describes some strategies for counting by **calculating**.\n", + "# Preliminaries: Imports and Utilities\n", "\n", - "# Problem 1: Counting Sub-cubes\n", - "\n", - "We'll start with a really simple counting problem:\n", - "\n", - "> Given a cube with ***n*** sub-cubes on a side, how many total sub-cubes are there?\n", - "\n", - "Here are two example cubes:\n", - "\n", - "|*n* = 3|*n* = 9|\n", - "|-----|-----|\n", - "| ![cube](https://qph.fs.quoracdn.net/main-qimg-a1eb70317e94431c265fb32c9ec2170f.webp) | ![cube](https://www.jugglingwholesale.com/media/catalog/product/cache/1/image/366x366/9df78eab33525d08d6e5fb8d27136e95/v/-/v-udoku.jpg) |\n", - "\n", - "\n", - "For the *n* = 3 cube, we could use the **enumeration** strategy, pointing to each sub-cube with our finger and counting 1, 2, 3, ... 27. That wouldn't work as well for the *n* = 9 cube, and it would be completely infeasible for an *n* = 1000 cube. How can we count with a computer?\n", - "\n", - "First let's get some Python preliminaries out of the way: imports, and three utility functions:\n", - "- `cat` concatenates strings into one big string\n", - "- `quantify` (from [the `itertools` module recipes](https://docs.python.org/3/library/itertools.html)) counts how many things a predicate is true for.\n", - "- `totalcount` totals up all the values in a Counter." + "Before getting started, here are the necessary imports, and four oft-used utility functions:\n", + "- `quantify` (from [the `itertools` module recipes](https://docs.python.org/3/library/itertools.html)) takes a collection of things and a predicate and counts for how many things the predicate is true. It is designed for the **enumerate and test** strategy, but can be used for the **brute force enumeration** strategy by omitting the optional predicate (as long as none of the things you want to count are false (like `0` or the empty string).\n", + "- `total` totals up all the values in a `dict` or `Counter`. Helpful because `sum(counter)` would sum the keys, not the values.\n", + "- `iterate`: The pattern of repeatedly calling a function *n* times will be common in this notebook; `iterate(f, x, n)`, a function [borrowed](https://hackage.haskell.org/package/base-4.14.0.0/docs/Prelude.html#v:iterate) from Haskell, encapsulates the pattern.\n", + "- `same`: Tests if two functions return the same output for all the given inputs." ] }, { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ - "# Python 3.x imports, and some utilities\n", - "\n", - "from collections import Counter\n", + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "import random\n", + "from collections import Counter, namedtuple\n", "from functools import lru_cache\n", - "from itertools import product, permutations, combinations\n", - "from math import factorial, inf # infinity\n", - "import re\n", - "\n", - "cat = ''.join\n", + "from itertools import product, permutations, combinations, islice\n", + "from math import factorial, log\n", + "from statistics import mean, stdev\n", + "from sys import maxsize\n", "\n", "def quantify(iterable, predicate=bool) -> int: \n", - " \"Count the number of items in iterable for which the predicate is true.\"\n", - " return sum(map(predicate, iterable)) \n", + " \"\"\"Count the number of items in iterable for which the predicate is true.\"\"\"\n", + " return sum(1 for item in iterable if predicate(item)) \n", "\n", - "def totalcount(counter) -> int:\n", - " \"The sum of all the values in a Counter (or mapping).\"\n", - " return sum(counter.values())" + "def total(counter) -> int:\n", + " \"\"\"The sum of all the values in a Counter (or dict or other mapping).\"\"\"\n", + " return sum(counter.values())\n", + "\n", + "def iterate(f, x, n) -> object:\n", + " \"\"\"Return f^n(x); for example, iterate(f, x, 3) == f(f(f(x))).\"\"\"\n", + " for _ in range(n):\n", + " x = f(x)\n", + " return x\n", + "\n", + "def same(fn1, fn2, inputs) -> bool:\n", + " \"\"\"Verify whether fn1(x) == fn2(x) for all x in inputs.\"\"\"\n", + " return all(fn1(x) == fn2(x) for x in inputs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Here is an **enumeration** strategy and a **calculation** strategy for sub-cube counting:" + "# Problem: Counting Barcodes\n", + "\n", + "> A typical barcode is pictured below. A valid barcode consists of alternating black and white stripes, where each stripe is either 1, 2, or 3 units wide. For a box that is *n* units wide, how many different valid barcodes are there?\n", + "\n", + "![barcode](https://help.shopify.com/assets/manual/sell-in-person/hardware/barcode-scanner/1d-barcode-4fbf513f48675746ba39d9ea5078f377e5e1bb9de2966336088af8394b893b78.png)\n", + "\n", + "We'll represent a unit as a character, `'B'` or `'W'`, and a barcode as a string of *n* units. The barcode above would start with `'BWWBW...'`. A valid string is one without 4 of the same character/unit in a row; `valid_barcode` tests for this.\n", + "\n", + "We'll start with the **enumerate and test** strategy: generate `all_strings` of *n* units and count how many are valid with `enumerate_barcodes`:" ] }, { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ - "def enumerate_subcubes(n) -> int: \n", - " return quantify(1 for width in range(n) \n", - " for depth in range(n) \n", - " for height in range(n))\n", + "def enumerate_barcodes(n) -> int: \n", + " \"\"\"Enumerate all barcodes of n units and count how many are valid.\"\"\"\n", + " return quantify(all_strings('BW', n), valid_barcode)\n", "\n", - "def calculate_subcubes(n) -> int: \n", - " return n ** 3" + "def all_strings(alphabet, n): \n", + " \"\"\"All strings of length n over the given alphabet.\"\"\"\n", + " return {''.join(chars) for chars in product(alphabet, repeat=n)}\n", + "\n", + "def valid_barcode(code) -> bool: \n", + " \"\"\"A valid barcode does not have 4 or more of the same unit in a row.\"\"\"\n", + " return 'BBBB' not in code and 'WWWW' not in code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The calculation strategy is *much* faster:" + "Here are all the strings of length 3:" ] }, { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 6.4 s, sys: 79.7 ms, total: 6.48 s\n", - "Wall time: 7.77 s\n" - ] - }, { "data": { "text/plain": [ - "27000000" + "{'BBB', 'BBW', 'BWB', 'BWW', 'WBB', 'WBW', 'WWB', 'WWW'}" ] }, "execution_count": 3, @@ -122,763 +129,20 @@ } ], "source": [ - "%time enumerate_subcubes(300)" + "all_strings('BW', 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a table of counts of valid barcodes for small values of *n*:" ] }, { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 5 µs, sys: 1 µs, total: 6 µs\n", - "Wall time: 9.06 µs\n" - ] - }, - { - "data": { - "text/plain": [ - "27000000" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%time calculate_subcubes(300)" - ] - }, - { - "cell_type": "markdown", "metadata": {}, - "source": [ - "\n", - "\n", - "# Problem 2: Counting Student Records (Late/Absent/Present)\n", - "\n", - "A more difficult problem:\n", - "\n", - "> Students at a school must check in with the guidance counselor if they have two total absences, or three consecutive late days. Each student's attendance record consists of a string of 'A' for absent, 'L' for late, or 'P' for present. For example: \"LAPLPA\" requires a meeting (because there are two absences), and \"LAPLPL\" is OK (there are three late days, but they are not consecutive). How many attendance records of length *n* are OK?\n", - "\n", - "The **enumeration** strategy says: define what it means for a record to be `ok`, define all the strings of length *n*, and count how many of them are `ok`:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: 1,\n", - " 1: 3,\n", - " 2: 8,\n", - " 3: 19,\n", - " 4: 43,\n", - " 5: 94,\n", - " 6: 200,\n", - " 7: 418,\n", - " 8: 861,\n", - " 9: 1753,\n", - " 10: 3536}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def ok(record: str) -> bool: \n", - " \"Is this student record OK? (Not 2 abscences, nor 3 consecutive lates.)\"\n", - " return not re.search(r'A.*A|LLL', record)\n", - "\n", - "def all_strings(alphabet, n): \n", - " \"All length-n strings over the given alphabet.\"\n", - " return map(cat, product(alphabet, repeat=n))\n", - "\n", - "def enumerate_ok(n) -> int:\n", - " \"How many attendance records of length n are ok?\"\n", - " return quantify(all_strings('LAP', n), ok)\n", - "\n", - "{n: enumerate_ok(n) for n in range(11)}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This looks good, but for large values of *n*\n", - "I will need an efficient **calculation** strategy. Here's how I think about it:\n", - "\n", - "* I can't enumerate all the strings; there are too many of them. \n", - "* Instead, I want to **divide and conquer**: divide the problem up into simpler subproblems, solve the subproblems, and combine them. A good way to divide this problem is to solve the case for *n* by first solving the case for *n*-1.\n", - "* With the enumeration strategy, going from *n*-1 to *n* multiplies the amount of work by 3 (because you have to consider any of three letters tacked on to the end of every possible record). \n", - "* With the right divide and conquer strategy, we can get from *n*-1 to *n* with a constant amount of work. So the total complexity can be *O*(*n*) instead of *O*(3*n*). \n", - "* (This divide and conquer strategy is sometimes called *[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)*, although some writers reserve the term *dynamic programming* for algorithms that explicitly store partial results in a table.)\n", - "* How do I get from *n*-1 to *n*? I will keep track of a *summary* of all the `ok` strings of length *n*-1, and use that to quickly (in constant time) compute a summary of the `ok` strings of length *n*. \n", - "* What is in the summary? A list of all `ok` strings is too much. A simple count of the number of `ok` strings is not enough. Instead, I need several different counts, for several different classes of strings. Each class is defined by the number of `'A'` characters in the string, and the number of consecutive `'L'` characters at the *end* of the string (because these are the two things that determine whether the string will be `ok` or not `ok` when I add a letter to the end). So the summary can be represented as a `Counter` of the form `{(A, L): count, ...}`. \n", - "\n", - "For *n* = 0, the summary is `{(0, 0): 1}`, because there is one string of length zero, the empty string, which has no `'A'` nor `'L'` in it. From there we can proceed in a \"bottom-up\" fashion to compute the total number of `ok` strings for the next value of `n`, using the function `next_summary`, which says that we can add an `'A'` to any string that doesn't already have one; we can add an `L` to any string that doesn't already end in 2 `'L'`s; and we can add a `'P'` to any string." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "summary0 = Counter({(0, 0): 1})\n", - "\n", - "def next_summary(prev_summary: Counter) -> Counter:\n", - " \"Given a summary of the form {(A, L): count}, return summary for one letter more.\"\n", - " summary = Counter()\n", - " for (A, L), count in prev_summary.items():\n", - " if not A: summary[A+1, 0] += count # add an 'A'\n", - " if L < 2: summary[A, L+1] += count # add an 'L'\n", - " summary[A, 0] += count # add a 'P'\n", - " return summary" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Counter({(0, 0): 1, (0, 1): 1, (1, 0): 1})" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next_summary(summary0)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Counter({(0, 0): 2, (0, 1): 1, (0, 2): 1, (1, 0): 3, (1, 1): 1})" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next_summary(_)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Counter({(0, 0): 4, (0, 1): 2, (0, 2): 1, (1, 0): 8, (1, 1): 3, (1, 2): 1})" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next_summary(_)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here's an implementation of `calculate_ok`, and a demonstration that it gets the same results as `enumerate_ok`:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def calculate_ok(n) -> int:\n", - " \"How many strings of length n are ok?\"\n", - " summary = summary0\n", - " for _ in range(n):\n", - " summary = next_summary(summary)\n", - " return totalcount(summary) " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: 1,\n", - " 1: 3,\n", - " 2: 8,\n", - " 3: 19,\n", - " 4: 43,\n", - " 5: 94,\n", - " 6: 200,\n", - " 7: 418,\n", - " 8: 861,\n", - " 9: 1753,\n", - " 10: 3536}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "{n: calculate_ok(n) for n in range(11)}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But we can go way beyond what we could do with `enumerate_ok`:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "744860152388838641467766615047636640123287960024109564468341118067976387620845421483777039844936500522445420732911099270409841757052659" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_ok(500)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Alternative: Abstraction with `iterate`\n", - "\n", - "This pattern of repeatedly calling `next_summary` *n* times will be common in this notebook; we can encapsulate it in a function called `iterate` (after the Haskell function of that name) allowing us to implement a version of `calculate_ok` in one line:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def calculate_ok2(N): return totalcount(iterate(next_summary, summary0, N))\n", - "\n", - "def iterate(f, x, n):\n", - " \"Return f^n(x); for example, iterate(f, x, 3) == f(f(f(x))).\"\n", - " for _ in range(n):\n", - " x = f(x)\n", - " return x" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "744860152388838641467766615047636640123287960024109564468341118067976387620845421483777039844936500522445420732911099270409841757052659" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_ok2(500)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Alternative: Working Down\n", - "\n", - "As a third alternative, instead of working up from 0 to `n` we can work down from `n` to 0 (although we may run up against Python's recursion limit):" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def calculate_ok3(n) -> int: return totalcount(nth_summary(n))\n", - " \n", - "def nth_summary(n) -> Counter: \n", - " \"The {(A, L): count} summary for strings of length n.\"\n", - " return (summary0 if n == 0 else next_summary(nth_summary(n - 1)))" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "744860152388838641467766615047636640123287960024109564468341118067976387620845421483777039844936500522445420732911099270409841757052659" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_ok3(500)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A comparison:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The slowest run took 4.34 times longer than the fastest. This could mean that an intermediate result is being cached.\n", - "100 loops, best of 3: 6.26 ms per loop\n", - "100 loops, best of 3: 9.52 ms per loop\n", - "100 loops, best of 3: 5.52 ms per loop\n" - ] - }, - { - "data": { - "text/plain": [ - "7.448601523888386e+134" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n = 500\n", - "%timeit calculate_ok(n)\n", - "%timeit calculate_ok2(n)\n", - "%timeit calculate_ok3(n)\n", - "float(calculate_ok(n))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are over 10134 ok strings of length 500, but it only takes a couple milliseconds to count them. Any of the three methods works equally well; use the approach you feel comfortable with." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Problem 3: Counting Strings with Alphabetic First Occurences\n", - "\n", - "Here's another problem:\n", - "\n", - "> How many strings of length *k* can be formed such that the first occurrences of each character in the string forms a prefix of the alphabet?\n", - "\n", - "Let's first make sure we understand the problem, because the statement is a bit abstract and tricky. Given a string we have to pick out the first occurrences of characters (letters). For example, for the string `\"abba\"`, we read left-to-right, recording each time we see a letter for the first time; that gives us `\"ab\"` (the subsequent occurrences of `'a'` and `'b'` don't matter). Is that a prefix of the alphabet, `\"abcd...\"`? Yes it is. \n", - "\n", - "Here are some test cases—pairs of strings along with their first occurrences—labelled with `True` for valid strings and `False` for invalid:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "alpha_test_cases = {\n", - " True: {('abba', 'ab'),\n", - " ('', ''),\n", - " ('a', 'a'),\n", - " ('aaa', 'a'),\n", - " ('abc', 'abc'),\n", - " ('abac', 'abc'),\n", - " ('abbacabbadabba', 'abcd')},\n", - " False: {('b', 'b'), # 'a' is missing\n", - " ('cab', 'cab'), # 'c' is before 'ab'\n", - " ('abd', 'abd'), # 'c' is missing\n", - " ('aback', 'abck'), # 'k' is before 'd-j'\n", - " ('badcafe','badcfe'), # 'b' is before 'a', etc.\n", - " ('abecedarian', 'abecdrin')}} # 'e' is before 'cd', etc." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now to implement the code that can run these tests. Since *k* could be arbitrarily large, I will by default assume an alphabet consisting of the non-negative integers, not the letters. Here are the key concepts:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "integers = range(10 ** 100)\n", - "letters = 'abcdefghijklmnopqrstuvwxyz'\n", - "\n", - "def is_alpha_firsts(s, alphabet=integers) -> bool: \n", - " \"Do the first occurrences of `s` form a prefix of the alphabet?\"\n", - " pre = firsts(s)\n", - " return pre == list(alphabet[:len(pre)]) \n", - "\n", - "def firsts(s) -> list: \n", - " \"The first occurrences of each character, in the order they appear.\"\n", - " return sorted(set(s), key=lambda x: s.index(x)) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "I'll test this code on the examples I showed above by defining the function `alpha_test`:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'pass'" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def alpha_test(cases=alpha_test_cases):\n", - " \"Verify all the test cases.\"\n", - " for validity in cases:\n", - " for (s, s_firsts) in cases[validity]:\n", - " assert firsts(s) == list(s_firsts)\n", - " assert is_alpha_firsts(s, letters) == validity\n", - " return 'pass'\n", - "\n", - "alpha_test()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now I can count the number of valid strings by enumerating all possible strings in the alphabet and checking each one with `is_alpha_firsts`. The complexity of this algorithm is $O(k^{k+1})$, because there are $k^k$ strings, and to validate a string requires looking at all $k$ characters:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: 1, 1: 1, 2: 2, 3: 5, 4: 15, 5: 52, 6: 203}" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def enumerate_alpha_firsts(k) -> int: \n", - " \"\"\"Enumerate all possible strings and count the number of valid ones.\"\"\"\n", - " all_strings = product(range(k), repeat=k)\n", - " return quantify(all_strings, is_alpha_firsts)\n", - "\n", - "{k: enumerate_alpha_firsts(k) for k in range(7)}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's think about a **calculation** strategy that would be faster than the **enumeration** strategy.\n", - "As with previous problems, I need a *summary* of the relevant information for strings of length *k*, to help me calculate the relevant information for length *k*+1. I know that if I have a valid string of length *k* with *m* distinct characters in it, then I can extend it by one character in *m* ways by repeating any of those *m* characters, or I can introduce a first occurrence of character number *m+1* (but I can do that in just 1 way). I can't validly introduce any other character. So a good summary would be a Counter of `{`*m*`: `*count*`}`, and we get this:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def calculate_alpha_firsts(k): \n", - " \"Count the number of strings of length k that have alphabetic first character occurrences.\"\n", - " return totalcount(iterate(next_alpha_summary, {0: 1}, k))\n", - "\n", - "def next_alpha_summary(prev_summary) -> Counter:\n", - " \"Given a summary of the form {m: count}, return summary for one character more.\"\n", - " summary = Counter()\n", - " for m, c in prev_summary.items():\n", - " summary[m] += c * m # Add any of the m previously-used characters\n", - " summary[m + 1] += c # Add character number m+1\n", - " return summary" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: 1, 1: 1, 2: 2, 3: 5, 4: 15, 5: 52, 6: 203}" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "{k: calculate_alpha_firsts(k) for k in range(7)}" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "29899013356824084214804223538976464839473928098212305047832737888945413625123259596641165872540391578300639147082986964028021802248993382881013411276574829121155811755170830666039838837273971971676782389800810361809319250755399325279656765435255999301529770267107281619733800281695881540007577899106878679451165492535930459233713316342551545242815802367257284852612201081016386308535990145447341800455472334713864080523978960296365736999295932080550928561633025800627524911700149562106895897725047744775812241800937310491797818107578233924187312824632629095993832334781713007323483688294825326897450386817327410532925074613888321264138083842196202242956001314953449497244271843922741908252107652201346933889741070435350690242062001522697855278356012055718392851567813397125419144780476479197990921602015873703820769182603836788465785093563686025690269802153802436873530877006737154523895273029510238745997356292232631282773748762989386003970214423843947094021177989737557020369751561595003372955621411858485959813344799967960196238368337022346946771703060269288691694028444791203978533454759410587065022546491518871238421560825907135885619221776405898771057270555581449229994215739476758785884545723062263992367750091319644861547658472282284005892044371587560711880627741139497818835632120761570174928529697397267899554407350161283097123211048049269727655279783900702416095132827766428865017653366696304131436690232979453876337599721772897049270230544262611264917393374756384152784943607952408782612639220380791445272655004475989064276373713608901650681165467490310898804916827069427310961109285035545084791339423266482359955663377201515204340817580915468489969181643341007197836481461051798995640789292580146918580703759556634019451731530034209189203377522668309771129566108101617727442045637098112678864654309987785463307376544339506878267267349348171320834971956806668304099159992067385998690820326902473886782781499414773179" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_alpha_firsts(1000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "That's a big number.\n", - "\n", - "# Alternative: Recursion\n", - "\n", - "Another way to keep track of the number of valid strings of length *k* with *m* distinct characters is with a recursive counting function, which I will call `C(k, m)`. There are three cases: \n", - "\n", - "- `C(0, 0)` is 1, because the empty string is valid (and contains no distinct characters). \n", - "- `C(k, m)` is 0 when `k` is negative (because there is no such thing as a negative length string) or less than `m` (because a string can't contain more distinct characters than its length). \n", - "- Otherwise, there are `m` ways to add an existing letter to each of the strings of length `k - 1`, and there is one way to add a new letter." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "@lru_cache(None)\n", - "def C(k, m) -> int:\n", - " \"Count the number of valid strings of length k, that use m distinct characters.\"\n", - " return (1 if (k == m == 0) else\n", - " 0 if (k < 0 or k < m) else\n", - " m * C(k - 1, m) + C(k - 1, m - 1))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that I used `lru_cache`, to avoid having to re-compute intermediate results.\n", - "\n", - "Now I can define `calculate_alpha_firsts2(k)` as the sum of `C(k, m)` over all values of `m`:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def calculate_alpha_firsts2(k) -> int: return sum(C(k, m) for m in range(k + 1))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's make sure the two calculations gives the same answers as the enumeration, at least for small values of $k$:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all(enumerate_alpha_firsts(k) == calculate_alpha_firsts(k) == calculate_alpha_firsts2(k)\n", - " for k in range(7))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Problem 4: Counting Barcodes\n", - "\n", - "> Consider the barcode pictured below. A valid barcode consists of alternating black and white stripes, where each stripe is either 1, 2, or 3 units wide. The question is: for a box that is *n* units wide, how many different valid barcodes are there?\n", - "\n", - "![barcode](https://help.shopify.com/assets/manual/sell-in-person/hardware/barcode-scanner/1d-barcode-4fbf513f48675746ba39d9ea5078f377e5e1bb9de2966336088af8394b893b78.png)\n", - "\n", - "We'll represent a barcode as a string, such as `'BBWWWBBW'`. Each of the *n* characters in the string can be either `'B'` or `'W'`, but the string can't have 4 of the same character in a row. We'll start with the familiar enumerate-and-test strategy:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def valid_barcode(code) -> bool: return 'BBBB' not in code and 'WWWW' not in code\n", - "\n", - "def all_barcodes(n): return map(cat, product('BW', repeat=n))\n", - "\n", - "def enumerate_barcodes(n) -> int: return quantify(all_barcodes(n), valid_barcode)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here's a table of counts for small values of *n*:" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false - }, "outputs": [ { "data": { @@ -898,7 +162,7 @@ " 12: 1854}" ] }, - "execution_count": 29, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -911,34 +175,800 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can see that the table starts out with the powers of two: 1, 2, 4, 8. That makes sense: each of the *n* positions in the barcode could be either black or white, so that's 2*n* barcodes. But barcodes with 4 or more of the same color in a row are invalid, so for *n* = 4, `'BBBB'` and `'WWWW'` are invalid, and we get 14 (not 16) valid barcodes. For *n* = 5 and up, the difference between 2*n* and the count of valid barcodes becomes larger.\n", + "This approach enumerates a lot of strings that can't possibly be valid. For example, there are 1024 strings of length 14 that start with `'BBBB...'` and none of them are valid. We could save a lot of time if we stopped generating such strings after we see the `'BBBB'`. \n", "\n", - "Now for a fast **calculation**. As before, we need a representation that summarizes the valid barcodes of length *n*. The key thing we need to know is how many barcode units of the same color are at the *end* of the barcode: if it is 1 or 2, then we can add another instance of the same color to the end; no matter what it is we can always add the opposite color (and then the barcode will end in just one unit of the same color)." + "The **incremental enumeration** strategy starts with all the valid strings of length 0 (there is only one, the empty string), and then repeats *n* times the process of appending one unit (`'B'` or `'W'`) to each string, if that append would be valid." ] }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def incremental_count_barcodes(n): \n", + " \"\"\"Count how many barcodes of length n are valid.\"\"\"\n", + " barcodes = {''}\n", + " for _ in range(n):\n", + " barcodes = extend_barcodes(barcodes)\n", + " return len(barcodes)\n", + "\n", + "def extend_barcodes(barcodes) -> set:\n", + " \"\"\"All valid ways to add one unit to each of a set of barcodes.\"\"\"\n", + " return {barcode + unit for barcode in barcodes for unit in 'BW'\n", + " if not barcode.endswith(3 * unit)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The four lines of code in the body of `incremental_count_barcodes` are exactly the pattern encapsulated in the `iterate` higher-order function. So we can rewrite `incremental_count_barcodes` with a one-line body:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def incremental_count_barcodes(n): \n", + " \"\"\"Count how many barcodes of length n are valid.\"\"\"\n", + " return len(iterate(extend_barcodes, {''}, n))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try it:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1854" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "incremental_count_barcodes(12)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Verify that the results are the same for small *n*:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "same(enumerate_barcodes, incremental_count_barcodes, range(13))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's how I think about a more efficient approach:\n", + "* I can use **abstract incremental enumeration**: find a representation that summarizes all the barcodes of length zero, then incremently extend that summary to get a summary of the barcodes of length 1. Do that *n* times.\n", + "* At each step, the key information that needs to be in the summary is how many barcode units of the same color are at the *end* of a barcode: if it is 1 or 2, then we can add another instance of the same color to the end. If it is 3, we cannot. We can always add the opposite color, and then the resulting barcode will end in just one unit of the same color. \n", + "* Thus, the summary will be a list of four counts: `[e0, e1, e2, e3]`, where `ei` gives the number of strings that end in `i` units of the same color. \n", + "* To take this summary and extend it by one unit to make the next summary:\n", + " - For all the counts except `e3` we could add a unit of the same color; that would show up in the next higher position (e.g. a count of 4 in `e1` would show up as a count of 4 in `e2` in the next summary).\n", + " - For all the counts, we could add a unit of the opposite color; the sum of them would show up in `e1` of the next summary.\n", + "* The function `abstract_barcodes(n)` does this update `n` times (using `iterate`) and in the end takes the sum of the four counts in the summary.\n", + "* With **brute force enumeration**, incrementing *n* by 1 doubles the amount of work (because you double the number of candidate strings). With **incremental enumeration** there are fewer strings, but still an exponential number of them.\n", + "* With the **abstract incremental** approach, incrementing *n* by 1 does a constant amount of work. Thus the total complexity is *O*(*n*), instead of *O*(2*n*) for **brute force enumeration** and (we will see later) approximately *O*(1.8*n*) for **incremental enumeration**.\n", + "\n", + "We can code that up as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "barcodes0 = [1, 0, 0, 0] # Summary of ending-counts of barcodes of length n=0\n", + "\n", + "def abstract_barcodes(n) -> int: \n", + " \"\"\"Count how many barcodes of length n are valid.\"\"\"\n", + " return sum(iterate(extend_barcodesummary, barcodes0, n))\n", + "\n", + "def extend_barcodesummary(barcodes) -> list:\n", + " \"\"\"Given a summary of barcodes of length n, build a summary for length n+1.\"\"\"\n", + " e0, e1, e2, e3 = barcodes\n", + " return [0, sum(barcodes) + e0, e1, e2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Verify that we get the same results for small values of *n*:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "same(enumerate_barcodes, abstract_barcodes, range(20))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can examine the first few summaries:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: [1, 0, 0, 0],\n", + " 1: [0, 2, 0, 0],\n", + " 2: [0, 2, 2, 0],\n", + " 3: [0, 4, 2, 2],\n", + " 4: [0, 8, 4, 2],\n", + " 5: [0, 14, 8, 4],\n", + " 6: [0, 26, 14, 8],\n", + " 7: [0, 48, 26, 14],\n", + " 8: [0, 88, 48, 26],\n", + " 9: [0, 162, 88, 48]}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{n: iterate(extend_barcodesummary, barcodes0, n) for n in range(10)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`abstract_barcodes` can quickly compute very big numbers that `enumerate_barcodes` could never handle:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 9.85 ms, sys: 235 µs, total: 10.1 ms\n", + "Wall time: 10.2 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "3861431277625007961956955484353530119634001892816040917233932945064320273497370215771811960744678098449553175356862760450029708838175822242262792740296878964074883622671541479265048463512360941352413049264274485743297728357502930085506419846119753743423275462450713981257123756695327534235952507322555045959925039572403245743061549541274972562526816439217931608999532601457740681763142591939324781110768274782850152125981385364637513839024687081770052346957401052189529936883629883775724870785833452510126377097128195647948735625551805771200981065390268401761158588370204299868440790417559363818139283430755197453196664541025472104658523804014518931760254828135638415413408780736125999685589725526874318196976263624936793335541955083569139572617638693840543637407782446933562063756941909207810703824222697116352937601482868529114899390708691493432262019965964035273813939182009029538539757438413668036430833988535147478776959903569999055599703304516221455076523484352182404159659661240973630499557250950477386781288167303525408434907471599633608826344342446869378392685927230076723348547049789748491137890119623879128231595262082532286126660730784998797003448161418183918024344043613986269574364002761796194720086663633818066518383357158900007727428966795190669943187944515210398817044521469661682433819382541570464313514353180507280999817655346753846288267575488232309682752190042235927387740555053797529717247933281707578234957297940957985028202675009617273305705968728942732545640071819447202821044438874136038990729299397246489481363094787623333269036228204295737689912072742922999093173704662567170601571800655678495878408411165386708197339087266092115780445248022350264528021426918011958029075557108406192634108388793426193565093359228830473466263938925653882623387099940055081548579900911968982480432787324594136156465497071249090902373689488770079828664684036332439902542305885855063306802357476735193730805776865978477463443216064890685565824039494431583860044254937057151591772329166180799218273949130368000609439119706131185925513231524378443124711002954768565310478734594199963723940004083846148186188631535346393565417946059827530465095391420721324513264443555308798011729355327067365885381721113676766083967129134309202588682281325857855165574371421168078423586430302604691681703448297310856061359072019641696782664700526740970642410648738647199882852824774480069658314840218244137906558931392021855430239022442215072063184370394666755160595637651648014842470092745788026900633378764049390511584307920491613532339464196985013369306439276245475602674051266814071448421271626238787893306176669816773478303604652043427279626683524358370" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time abstract_barcodes(10000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's a big number! And it only took about 10 milliseconds! How many digits is the result?" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2647" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def digits(n: int) -> int: return len(str(n))\n", + "\n", + "digits(abstract_barcodes(10000))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So the number of valid barcodes of length 10,000 is more than 102646. \n", + "\n", + "We can apply the **shoulders of giants** strategy and search for the first few numbers in the series, [\"1, 2, 4, 8, 14, 26, 48\"](https://www.google.com/search?q=%221%2C+2%2C+4%2C+8%2C+14%2C+26+48%22), and get as the first result the page [oeis.org/A135491](https://oeis.org/A135491), titled *Number of ways to toss a coin n times and not get a run of four*, which sounds right. [OEIS](https://oeis.org/), the On-Line Encyclopedia of Integer Sequences®, is a fantastic resource for all those who count things, and often shows up in searches like this." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "# Problem: Counting Student Records (Late/Absent/Present)\n", + "\n", + "> Students at a school must check in with the guidance counselor if they have three total absences, or three consecutive late days. Each student's attendance record consists of a string of 'A' for absent, 'L' for late, or 'P' for present. For example: \"LAPPLAA\" requires a meeting (because there are three absences), and \"LAPPLAL\" is OK (there are three late days, but they are not consecutive). How many attendance records of length *n* days are OK?\n", + "\n", + "The **brute force enumeration** strategy applies in a similar way to the previous problem. Define what it means for a record to be `ok`, generate all the strings of length *n*, and count how many of them are `ok`." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def ok(record: str) -> bool: \n", + " \"\"\"Is this student record OK? (Not 3 absences, nor 3 consecutive lates.)\"\"\"\n", + " return record.count('A') < 3 and 'LLL' not in record\n", + "\n", + "def enumerate_count_ok(n) -> int:\n", + " \"\"\"How many attendance records of length n are ok?\"\"\"\n", + " return quantify(all_strings('LAP', n), ok)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: 1,\n", - " 1: 2,\n", - " 2: 4,\n", - " 3: 8,\n", - " 4: 14,\n", - " 5: 26,\n", - " 6: 48,\n", - " 7: 88,\n", - " 8: 162,\n", - " 9: 298,\n", - " 10: 548,\n", - " 11: 1008,\n", - " 12: 1854}" + " 1: 3,\n", + " 2: 9,\n", + " 3: 25,\n", + " 4: 67,\n", + " 5: 171,\n", + " 6: 419,\n", + " 7: 994,\n", + " 8: 2296,\n", + " 9: 5188,\n", + " 10: 11510}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{n: enumerate_count_ok(n) for n in range(11)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This looks good, but there are 3*n* strings of length *n*, so for large values of *n*\n", + "we will need a more efficient strategy.\n", + "\n", + "* The **abstract incremental enumeration** strategy is again applicable: find a representation that summarizes all the attendance records of length zero, then incremently extend the length by 1, and do that *n* times. The function `abstract_count_ok` implements this approach, again using `iterate`.\n", + "* What is in the summary? A list of all `ok` records is too much. A simple count of the number of `ok` records is not enough. Instead, we need several different counts, for several different classes of records. Each class is defined by the number of `'A'` characters in the records, and the number of consecutive `'L'` characters at the *end* of the records, because these are the two things that determine whether the string will be `ok` or not `ok` when we add letters to the end). So the summary can be represented as a `Counter` of the form `{(A, L): count, ...}`. For example the summary `{(1, 2): 3, ...}` means that there are 3 `ok` records that contain one `'A'` and end in two `'L'`s. They records aren't explicitly named in the summary (that's why the summary can be efficient), but they would be `{'APLL', 'LALL', 'PALL'}`.\n", + "* For *n* = 0, the summary is `{(0, 0): 1}`: one record of length 0, the empty string, which has no `'A'` in it and no `'L'` at the end. \n", + "* The function `extend_one_day` says that we can add an `'A'` to any string that doesn't already have two `'A'`s; we can add an `L` to any string that doesn't already end in 2 `'L'`s; and we can add a `'P'` to any string." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "records0 = Counter({(0, 0): 1})\n", + "\n", + "def abstract_count_ok(n) -> int:\n", + " \"\"\"How many attendance records of length n are ok?\"\"\"\n", + " return total(iterate(extend_records, records0, n))\n", + "\n", + "def extend_records(records: Counter) -> Counter:\n", + " \"\"\"Given a summary of records of length n in the form {(A, L): count}, \n", + " build a summary of records of length n + 1.\"\"\"\n", + " next_records = Counter()\n", + " for (A, L), count in records.items():\n", + " if A < 2: next_records[A + 1, 0] += count # add an 'A'\n", + " if L < 2: next_records[A, L + 1] += count # add an 'L'\n", + " next_records[A, 0] += count # add a 'P'\n", + " return next_records" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Verify that `abstract_count_ok` gets the same counts as `enumerate_count_ok`:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "same(abstract_count_ok, enumerate_count_ok, range(11))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here are the first few summaries of records of length *n*:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: Counter({(0, 0): 1}),\n", + " 1: Counter({(1, 0): 1, (0, 1): 1, (0, 0): 1}),\n", + " 2: Counter({(2, 0): 1,\n", + " (1, 1): 1,\n", + " (1, 0): 3,\n", + " (0, 2): 1,\n", + " (0, 0): 2,\n", + " (0, 1): 1}),\n", + " 3: Counter({(2, 1): 1,\n", + " (2, 0): 5,\n", + " (1, 2): 1,\n", + " (1, 0): 8,\n", + " (1, 1): 3,\n", + " (0, 0): 4,\n", + " (0, 1): 2,\n", + " (0, 2): 1})}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{n: iterate(extend_records, records0, n) for n in range(4)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, the entry for `1:` says there are 3 total strings of length one; one of which contains 1 `A` and does not end in `L`; one of which does not contain an `A` and does end in one `L`, and one of which has neither `A` nor `L`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of course `abstract_count_ok` can go *way* beyond what we could do with `enumerate_count_ok`:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "67915092244946245526761121539961065667354710339484389403398502322665903317227269563431987985548850569926132622865368781540197647175409335204446318662764534903563777210453736211255159314858993923969786046819296950933246810634303897405512752272032426651642064888476180415506912693513909342933046331038474619509081763784765550352067334165901573244296556383159625556197148091705165182887658871588760415124598528254895046939766294908991602550833585558872584109925815975563950518270492886424386418887038225367557977580598940456529146317404617930359322164816128982301399847355494961116547323299531092346924090578848490063810929726294235553624714771568277381300778770044740403839922522259903425992438105556328232190837523076945505837289570218129815218657504553108186081068344280320487112129980538558330653940927620274198611870978884765113302222147574340037452775946171158479481569109577479495284213988633469847097599897091262353972939940610742973967768665639608260138071788253672077302950170544573659098025328249386699113294464533042986243917770015922628745694209690218902434289336799469726583915592005603572447725365675690796428672725349270535435510404530717474913302992334196693282513211071037040630045078690538568866750760269179165191419371245126202447626783645521606741196697550515070422233997330690541032248272343548507506077080632447162616725116827906765346068097284144021799385759481910334161557352438965487177479943712008492652355168983678944082674396835412877102701320156716226396792442810305911973460027845758272368905315276808267770968165158601228698100671353970870820495437717365750878332077859999742716730188128437024395707454371180819695507850153005101353643954347256441396183843055876562258195012627902932249519909390770919657440052840040197024105521065595910086035192717059260479461379754157116341147835641061318945374959021427192475455471423853727585174268760196347849181893783510713204119256033951950166887204536135896283786882669204124059336236100878907356839002912187712588976111620701336082598908391856751671391768146332236193267088262535153912806255587921455005824532343009909950356632076138892829754315844530603374067069772173161102995334001987128851407630096692078344942645715716941016099638170178149988009446531234694691215930910342787376545269610229494026686126796325578380820170813105262828560980051029484551420232365099464095174864505651859406571715076351131405366919080277275366319781500406689243537529390550548233759064314753797975451923281566305080203709436529025198215417739606729647754826931823619915850794244671776741088055751566519186191628709222778000007816869534445057653832155401753050275129786525546204005123078586341515867" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abstract_count_ok(10000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That looks like a roughly similar number of digits as `abstract_barcodes(10000)`; let's compare:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2654, 2647)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "N = 10000\n", + "digits(abstract_count_ok(N)), digits(abstract_barcodes(N))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So `abstract_count_ok(10000)` is only 7 digits more than `abstract_barcodes(10000)`, out of 2654. \n", + "\n", + "I'm curious how close the two series are in general. I'll plot them on a log-plot and compare with $2^n$ and $1.8^n$ (I'll only go up to $n = 366$ days to avoid overflow, but the straight lines look the same at any $n$ values):" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def logplots(X, fns, xlabel='', ylabel=''): \n", + " \"\"\"Given fns={label: fn,...} plot fn(x) vs x for each fn.\"\"\"\n", + " plt.yscale('log'); plt.xlabel(xlabel); plt.ylabel(ylabel)\n", + " for label in fns:\n", + " plt.plot(X, [fns[label](x) for x in X], '-', label=label)\n", + " plt.legend()\n", + "\n", + "logplots(range(1, 367, 5), {\n", + " '2^n': (2).__pow__,\n", + " 'abstract_count_ok': abstract_count_ok,\n", + " 'abstract_barcodes': abstract_barcodes,\n", + " '1.8^n': 1.8.__pow__}, \n", + " 'Number of days', 'Number of Records')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Pirates Counting Coconuts\n", + "\n", + "The 538 Riddler poses [this problem](https://fivethirtyeight.com/features/pirates-monkeys-and-coconuts-oh-my) (slightly edited):\n", + "\n", + ">Seven pirates wash ashore on a deserted island. They gather coconuts into a central pile. As the sun sets, they all go to sleep.\n", + ">\n", + ">One pirate wakes up in the middle of the night. Being greedy, this pirate decides to take some coconuts from the pile and hide them for himself. As he approaches the pile, though, he notices a monkey watching him. To keep the monkey quiet, the pirate tosses it one coconut from the pile. He then divides the rest of the pile into seven equal bunches and hides one of the bunches in the bushes. Finally, he recombines the remaining coconuts into a single pile and goes back to sleep.\n", + ">\n", + ">In succession, each of the pirates does the same routine. In the morning, the pirates split the pile into seven equal bunches and take one bunch each. (The monkey does not get one this time.)\n", + ">\n", + ">If there were *c* coconuts in the pile originally, what is the smallest possible value of *c*? What is *c* if there are *p* pirates?\n", + "\n", + "At least for *p* = 7, it seems like an **enumerate and test** approach should work, where we enumerate the number of coconuts, *c* and check if each amount can be evenly divided multiple times as the story dictates. The function `coconuts_divisible` does the check and `enumerate_coconuts` enumerates values of *c* and returns the first one that works. We can be somewhat clever in the enumeration: we know that the first pirate throws one coconut to the monkey and then the pile is divisible by *p*. So the only numbers we need to consider for *c* are of the form *kp* + 1, which we write in Python as `range(1, maxsize, p)`." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "def enumerate_coconuts(p=7) -> int:\n", + " \"\"\"Find the smallest number of coconuts, c, that makes the story work for p pirates.\"\"\"\n", + " return next(c for c in range(1, maxsize, p) if coconuts_divisible(p, c))\n", + "\n", + "def coconuts_divisible(p, c) -> bool:\n", + " \"\"\"Can p pirates divide c coconuts evenly, following the steps of the story?\"\"\"\n", + " for pirate in range(p): # Each successive pirate\n", + " c -= 1 # tosses the monkey one coconut\n", + " if not divides(p, c): # divides the rest of the pile into p equal bunches\n", + " return False\n", + " c -= c // p # and hides one bunch\n", + " return divides(p, c) # In the morning they split the pile evenly.\n", + " \n", + "def divides(P, C) -> bool: return C % P == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "823537" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enumerate_coconuts(7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's a big pile of coconuts. Let's see how many coconuts are needed with fewer pirates:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 3, 25, 765, 3121, 233275, 823537]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[enumerate_coconuts(p) for p in range(1, 8)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The **shoulders of giants** search \n", + "[\"1, 3, 25, 765, 3121\"](https://www.google.com/search?q=%221+3+25+765+3121%22&oq=%221+3+25+765+3121%22)\n", + "yields as first result [oeis.org/A002021](https://oeis.org/A002021), titled \"Pile of coconuts problem\" so that is definitely the right page. The page gives a **formula calculation**:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_coconuts(p) -> int:\n", + " \"\"\"Find the smallest number of coconuts that makes the story work for p pirates.\"\"\"\n", + " return (p - 1) * (p ** p - 1) if divides(2, p) else p ** p - p + 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can verify the formula and use it to explore bigger numbers:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: 1,\n", + " 2: 3,\n", + " 3: 25,\n", + " 4: 765,\n", + " 5: 3121,\n", + " 6: 233275,\n", + " 7: 823537,\n", + " 8: 117440505,\n", + " 9: 387420481,\n", + " 10: 89999999991,\n", + " 11: 285311670601,\n", + " 12: 98077104930805,\n", + " 13: 302875106592241,\n", + " 14: 144456088732254195,\n", + " 15: 437893890380859361,\n", + " 16: 276701161105643274225,\n", + " 17: 827240261886336764161,\n", + " 18: 668888937280041138782191,\n", + " 19: 1978419655660313589123961,\n", + " 20: 1992294399999999999999999981,\n", + " 21: 5842587018385982521381124401,\n", + " 22: 7169985424648610705329581195243,\n", + " 23: 20880467999847912034355032910545,\n", + " 24: 30675922867556534862328873875406825,\n", + " 25: 88817841970012523233890533447265601,\n", + " 26: 153902989505178932769916857210005094375,\n", + " 27: 443426488243037769948249630619149892777,\n", + " 28: 894929124057841121289463662840844356943845,\n", + " 29: 2567686153161211134561828214731016126483441}" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "assert same(calculate_coconuts, enumerate_coconuts, range(1, 8))\n", + "\n", + "{p: calculate_coconuts(p) for p in range(1, 30)}" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "998999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999001" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "calculate_coconuts(1000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extension: Non-Minimal Numbers of Coconuts\n", + "\n", + "I'm curious what *other* numbers of coconuts *c* are possible, not just the minimal number for each *p*. Below I compute the 7 smallest values of *c* for each number of pirates *p* in the range 1-7:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: [1, 2, 3, 4, 5, 6, 7],\n", + " 2: [3, 11, 19, 27, 35, 43, 51],\n", + " 3: [25, 106, 187, 268, 349, 430, 511],\n", + " 4: [765, 1789, 2813, 3837, 4861, 5885, 6909],\n", + " 5: [3121, 18746, 34371, 49996, 65621, 81246, 96871],\n", + " 6: [233275, 513211, 793147, 1073083, 1353019, 1632955, 1912891],\n", + " 7: [823537, 6588338, 12353139, 18117940, 23882741, 29647542, 35412343]}" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def kcoconuts(p=7, k=7) -> [int]:\n", + " \"\"\"Find the k smallest number of coconuts, c, that makes the story work for p pirates.\"\"\"\n", + " return list(islice((c for c in range(1, maxsize, p) if coconuts_divisible(p, c)), k))\n", + "\n", + "{p: kcoconuts(p) for p in range(1, 8)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These numbers look like they're in arithmetic sequences (the same difference between each pair of adjacent numbers). I can test that:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "def arithmetic_sequence(numbers) -> tuple:\n", + " \"\"\"Are the numbers in an arithmetic sequence? Return the first and the differences.\"\"\"\n", + " deltas = {numbers[i] - numbers[i - 1] for i in range(1, len(numbers))}\n", + " return (numbers[0], deltas)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: (1, {1}),\n", + " 2: (3, {8}),\n", + " 3: (25, {81}),\n", + " 4: (765, {1024}),\n", + " 5: (3121, {15625}),\n", + " 6: (233275, {279936}),\n", + " 7: (823537, {5764801})}" ] }, "execution_count": 30, @@ -947,72 +977,483 @@ } ], "source": [ - "def calculate_barcodes(k): return totalcount(iterate(next_barcode_summary, {0: 1}, k))\n", - "\n", - "def next_barcode_summary(prev_summary) -> Counter:\n", - " \"Given a summary of the form {end: count}, return summary for one unit more.\"\n", - " summary = Counter()\n", - " for end, c in prev_summary.items():\n", - " if end < 3: \n", - " summary[end + 1] += c\n", - " summary[1] += c\n", - " return summary \n", - "\n", - "{k: calculate_barcodes(k) for k in range(13)}" + "{p: arithmetic_sequence(kcoconuts(p)) for p in range(1, 8)}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Verify that enumeration and calculation do the same thing for small values of *n*:" + "That confirms it (at least up to 7), and I see a pattern in the deltas: we have 2: 8 = 23, 3: 81 = 34, 4: 1024 = 45, etc. I can verify the pattern (at least up to 7):" ] }, { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "assert all(enumerate_barcodes(n) == calculate_barcodes(n) for n in range(20))" - ] - }, - { - "cell_type": "markdown", "metadata": {}, - "source": [ - "Demonstrate that we can compute big numbers:" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "collapsed": false - }, "outputs": [ { "data": { "text/plain": [ - "3861431277625007961956955484353530119634001892816040917233932945064320273497370215771811960744678098449553175356862760450029708838175822242262792740296878964074883622671541479265048463512360941352413049264274485743297728357502930085506419846119753743423275462450713981257123756695327534235952507322555045959925039572403245743061549541274972562526816439217931608999532601457740681763142591939324781110768274782850152125981385364637513839024687081770052346957401052189529936883629883775724870785833452510126377097128195647948735625551805771200981065390268401761158588370204299868440790417559363818139283430755197453196664541025472104658523804014518931760254828135638415413408780736125999685589725526874318196976263624936793335541955083569139572617638693840543637407782446933562063756941909207810703824222697116352937601482868529114899390708691493432262019965964035273813939182009029538539757438413668036430833988535147478776959903569999055599703304516221455076523484352182404159659661240973630499557250950477386781288167303525408434907471599633608826344342446869378392685927230076723348547049789748491137890119623879128231595262082532286126660730784998797003448161418183918024344043613986269574364002761796194720086663633818066518383357158900007727428966795190669943187944515210398817044521469661682433819382541570464313514353180507280999817655346753846288267575488232309682752190042235927387740555053797529717247933281707578234957297940957985028202675009617273305705968728942732545640071819447202821044438874136038990729299397246489481363094787623333269036228204295737689912072742922999093173704662567170601571800655678495878408411165386708197339087266092115780445248022350264528021426918011958029075557108406192634108388793426193565093359228830473466263938925653882623387099940055081548579900911968982480432787324594136156465497071249090902373689488770079828664684036332439902542305885855063306802357476735193730805776865978477463443216064890685565824039494431583860044254937057151591772329166180799218273949130368000609439119706131185925513231524378443124711002954768565310478734594199963723940004083846148186188631535346393565417946059827530465095391420721324513264443555308798011729355327067365885381721113676766083967129134309202588682281325857855165574371421168078423586430302604691681703448297310856061359072019641696782664700526740970642410648738647199882852824774480069658314840218244137906558931392021855430239022442215072063184370394666755160595637651648014842470092745788026900633378764049390511584307920491613532339464196985013369306439276245475602674051266814071448421271626238787893306176669816773478303604652043427279626683524358370" + "{1: 1, 2: 8, 3: 81, 4: 1024, 5: 15625, 6: 279936, 7: 5764801}" ] }, - "execution_count": 32, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_barcodes(10000)" + "{p: p ** (p + 1) for p in range(1, 8)}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Problem 5: Counting Rectangle Sets\n", + "So we can say the complete set of valid number of coconuts for a given number of pirates *p* is:\n", + " \n", + "- $(p - 1) × (p^p - 1) + k × p^{p+1}$ when $p$ is even, for any nonnegative integer $k$\n", + "- $p^p - p + 1 + k × p^{p+1}$ when $p$ is odd, for any nonnegative integer $k$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extension: Who Gets What?\n", + "\n", + "We can also count who gets what shares of the coconuts, by annotating the story. The monkey is individual 0, and the pirates are 1 to *p*:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "def coconuts_shares(p) -> dict:\n", + " \"\"\"Assuming p pirates divide coconuts evenly according to the story, who gets what share?\"\"\"\n", + " c = calculate_coconuts(p)\n", + " monkey = 0\n", + " pirates = range(1, p + 1)\n", + " shares = Counter()\n", + " def to(who, what): shares[who] += what; return what\n", + " for pirate in pirates: # Each successive pirate\n", + " c -= to(monkey, 1) # tosses the monkey one coconut\n", + " assert divides(p, c) # divides the rest of the pile into p equal bunches\n", + " c -= to(pirate, c // p) # and hides one bunch \n", + " for pirate in pirates: # In the morning they split the pile evenly.\n", + " to(pirate, c // p)\n", + " return dict(shares)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: 7,\n", + " 1: 157638,\n", + " 2: 140831,\n", + " 3: 126425,\n", + " 4: 114077,\n", + " 5: 103493,\n", + " 6: 94421,\n", + " 7: 86645}" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "coconuts_shares(7)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "assert total(_) == enumerate_coconuts(7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is best to be the first pirate; every other pirate does successively worse, with the last one getting about half of the first's share. The monkey always gets *p* coconuts from *p* pirates:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: {0: 1, 1: 0},\n", + " 2: {0: 2, 1: 1, 2: 0},\n", + " 3: {0: 3, 1: 10, 2: 7, 3: 5},\n", + " 4: {0: 4, 1: 251, 2: 203, 3: 167, 4: 140},\n", + " 5: {0: 5, 1: 828, 2: 703, 3: 603, 4: 523, 5: 459},\n", + " 6: {0: 6, 1: 51899, 2: 45419, 3: 40019, 4: 35519, 5: 31769, 6: 28644}}" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{p: coconuts_shares(p) for p in range(1, 7)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Counting Rhyme Schemes\n", + "\n", + "Here's another problem:\n", + "\n", + "> How many rhyme schemes are there for a *k* line poem? 'ABAB' is a valid rhyme scheme, as is 'ABBA', but 'BAAB' is not: in a valid rhyme scheme the first occurrences of each letter forms a prefix of the alphabet.\n", + "\n", + "Let's first make sure we understand what counts as a valid rhyme scheme. Given a string, first task pick out the **first occurrences** of letters. For example, for the string `\"ABAB\"`, we read left-to-right, recording each time we see a letter for the first time; that gives us `\"AB\"`; the subsequent occurrences of `'A'` and `'B'` don't matter. Given `\"BAAB\"`, the first occurrences are `\"BA\"`. Now we have to decide if these first occurrences form a **prefix of the alphabet**, `\"ABCD...\"`. For `\"AB\"` the answer is yes, but for `\"BA\"` the answer is no. \n", + "\n", + "Before we get to the counting, below are the basic concepts. Since we will want to go beyond *k* = 26, I will by default make the alphabet be the non-negative integers, so \"letters\" are integers. Use `alphabet` if you want strings of actual letters." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", + "\n", + "def is_rhyme_scheme(s, alphabet=range(maxsize)) -> bool: \n", + " \"\"\"Do the first occurrences of letters in `s` form a prefix of the alphabet?\"\"\"\n", + " return is_prefix(first_occurrences(s), alphabet)\n", + "\n", + "def is_prefix(short, long) -> bool:\n", + " \"\"\"Is the first argument a prefix of the second?\"\"\"\n", + " return all(S == L for S, L in zip(short, long))\n", + "\n", + "def first_occurrences(s) -> tuple: \n", + " \"\"\"The first occurrences of each character, in the order they appear.\"\"\"\n", + " return tuple(Counter(s)) # Counters preserve order of elements" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_rhyme_scheme('ABAB', alphabet)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_rhyme_scheme('BAAB', alphabet)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_rhyme_scheme('ABBACABBADABBA', alphabet)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_rhyme_scheme('ABBACABBADABBADO', alphabet)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can count the number of valid strings by **brute force enumeration**: generate all possible strings of length $k$ and check each one with `is_rhyme_scheme`. The complexity of this algorithm is $O(k^{k+1})$, because there are $k^k$ strings, and to validate a string requires looking at $k$ characters:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: 1, 1: 1, 2: 2, 3: 5, 4: 15, 5: 52, 6: 203, 7: 877}" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def enumerate_rhyme_schemes(k) -> int: \n", + " \"\"\"Enumerate all possible strings and count the number of valid rhyme schemes.\"\"\"\n", + " strings = product(range(k), repeat=k)\n", + " return quantify(strings, is_rhyme_scheme)\n", + "\n", + "{k: enumerate_rhyme_schemes(k) for k in range(8)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's think about an **abstract incremental enumeration** strategy.\n", + "As with previous problems, I need a *summary* of the relevant information for strings of length * k*, to help me calculate the relevant information for length * k*+1. I know that if I have a valid string of length * k* with *d* distinct characters in it, then I can extend it by one character in *d* ways by repeating any of those *d* characters, or I can introduce a first occurrence of character number *d+1* (but I can do that in just 1 way). I can't validly introduce any other character. So a good summary would be a Counter of `{d: count, ...}`. We start with strings of length 0, which have a summary of `{0: 1}` (one string, the empty string, with 0 distinct characters) and we get this:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "def abstract_rhyme_schemes(k) -> int: \n", + " \"\"\"Count the number of strings that are valid rhyme schemes.\"\"\"\n", + " return total(iterate(extend_rhymes, Counter({0: 1}), k))\n", + "\n", + "def extend_rhymes(counts) -> Counter:\n", + " \"\"\"Given a summary of the form {d: count}, return summary for one character more.\"\"\"\n", + " return Counter({d: d * counts[d] + counts[d - 1] \n", + " for d in range(len(counts) + 1)})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see the summary for strings of length *k* = 3:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Counter({0: 0, 1: 1, 2: 3, 3: 1})" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iterate(extend_rhymes, Counter({0: 1}), 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This says that for strings of length 3, there is 1 valid string with 1 distinct letter (which happens to be the string `'AAA'`, but the summary doesn't say that), 3 valid strings with 2 distinct letters (`'AAB', 'ABA', 'ABB'`) and 1 valid string with 3 distinct letters (`'ABC'`).\n", + "\n", + "We can show that this approach gives the same results as brute force enumeration (at least up to 7):" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "same(enumerate_rhyme_schemes, abstract_rhyme_schemes, range(8))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can see that this approach can handle much bigger values of *k*:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "29899013356824084214804223538976464839473928098212305047832737888945413625123259596641165872540391578300639147082986964028021802248993382881013411276574829121155811755170830666039838837273971971676782389800810361809319250755399325279656765435255999301529770267107281619733800281695881540007577899106878679451165492535930459233713316342551545242815802367257284852612201081016386308535990145447341800455472334713864080523978960296365736999295932080550928561633025800627524911700149562106895897725047744775812241800937310491797818107578233924187312824632629095993832334781713007323483688294825326897450386817327410532925074613888321264138083842196202242956001314953449497244271843922741908252107652201346933889741070435350690242062001522697855278356012055718392851567813397125419144780476479197990921602015873703820769182603836788465785093563686025690269802153802436873530877006737154523895273029510238745997356292232631282773748762989386003970214423843947094021177989737557020369751561595003372955621411858485959813344799967960196238368337022346946771703060269288691694028444791203978533454759410587065022546491518871238421560825907135885619221776405898771057270555581449229994215739476758785884545723062263992367750091319644861547658472282284005892044371587560711880627741139497818835632120761570174928529697397267899554407350161283097123211048049269727655279783900702416095132827766428865017653366696304131436690232979453876337599721772897049270230544262611264917393374756384152784943607952408782612639220380791445272655004475989064276373713608901650681165467490310898804916827069427310961109285035545084791339423266482359955663377201515204340817580915468489969181643341007197836481461051798995640789292580146918580703759556634019451731530034209189203377522668309771129566108101617727442045637098112678864654309987785463307376544339506878267267349348171320834971956806668304099159992067385998690820326902473886782781499414773179" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abstract_rhyme_schemes(1000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's a big number. \n", + "\n", + "A search for [\"1, 1, 2, 5, 15\"](https://www.google.com/search?q=%221%2C+1%2C+2%2C+5%2C+15%22) shows that this sequence is called [Bell numbers](https://en.wikipedia.org/wiki/Bell_number), and that they have lots of applications.\n", + "\n", + "## Version 2: Recursion\n", + "\n", + "Another way to keep track of the number of valid strings of length * k* with * d* distinct characters is with a recursive counting function, which I will call `count_rhymes(k, d)`. There are three cases: \n", + "\n", + "- `count_rhymes(0, 0)` is 1, because the empty string is valid (and contains no distinct characters). \n", + "- `count_rhymes(k, d)` is 0 when `k` is negative (because there is no such thing as a negative length string) or less than `d` (because a string can't contain more distinct characters than its length). \n", + "- Otherwise, there are `d` ways to add an existing letter to each of the strings of length `k - 1`, and there is one way to add a new letter." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "@lru_cache(None)\n", + "def count_rhymes(k, d) -> int:\n", + " \"\"\"Count the number of valid strings of length k, that use d distinct characters.\"\"\"\n", + " return (1 if (k == 0 == d) else\n", + " 0 if (k < 0 or k < d) else\n", + " d * count_rhymes(k - 1, d) + count_rhymes(k - 1, d - 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that I used `lru_cache`, to avoid having to re-compute intermediate results.\n", + "\n", + "Now I can define `calculate_rhyme_schemes(k)` as the sum of `count_rhymes(k, d)` over all values of `d`:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_rhyme_schemes(k) -> int: \n", + " \"\"\"Count the number of strings that are valid rhyme schemes.\"\"\"\n", + " return sum(count_rhymes(k, d) for d in range(k + 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's validate this:" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "same(abstract_rhyme_schemes, calculate_rhyme_schemes, range(101))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Counting Rectangle Sets\n", "\n", "This problem is covered in depth in [another notebook](Golomb-puzzle.ipynb), so here I present just the part that has to do with counting things:\n", "\n", @@ -1034,10 +1475,8 @@ }, { "cell_type": "code", - "execution_count": 33, - "metadata": { - "collapsed": false - }, + "execution_count": 49, + "metadata": {}, "outputs": [ { "data": { @@ -1045,7 +1484,7 @@ "945.0" ] }, - "execution_count": 33, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -1065,10 +1504,8 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": { - "collapsed": false - }, + "execution_count": 50, + "metadata": {}, "outputs": [ { "data": { @@ -1076,7 +1513,7 @@ "945" ] }, - "execution_count": 34, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1091,15 +1528,13 @@ "source": [ "(It is always a relief when two methods give the same answer.)\n", " \n", - "**Method 3: Write a program to enumerate and check:** We'll generate all permutations of sides, and then check which ones are valid rectangle sets: they must have the first element of each pair less than the second (i.e. A < B, C < D, ...) and the pairs must be sorted, which is equivalent to saying their first elements are sorted (i.e. A < C < E < G < I)." + "**Method 3: Write a program to enumerate and test:** We'll generate all permutations of sides, and then check which ones are valid rectangle sets: they must have the first element of each pair less than the second (i.e. A < B, C < D, ...) and the pairs must be sorted, which is equivalent to saying their first elements are sorted (i.e. A < C < E < G < I)." ] }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": false - }, + "execution_count": 51, + "metadata": {}, "outputs": [ { "data": { @@ -1107,13 +1542,14 @@ "945" ] }, - "execution_count": 35, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def valid_rectangle_set(sides):\n", + "def valid_rectangle_set(sides) -> bool:\n", + " \"\"\"Are the sides ordered according to convention?\"\"\"\n", " A,B, C,D, E,F, G,H, I,J = sides\n", " return A < B and C < D and E < F and G < H and I < J and A < C < E < G < I\n", "\n", @@ -1131,7 +1567,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Problem 6: Counting Paths on a Grid\n", + "# Problem: Counting Paths on a Grid\n", "\n", "> In a grid, how many paths are there from the upper left to the lower right corner, making only rightward or downward moves?\n", " \n", @@ -1146,15 +1582,13 @@ " \n", "We can use the same three methods as the previous problem:\n", "\n", - "**Method 1: Count all permutations and divide by repetitions:** Any path must consist of 10 right and 5 down moves, but they can appear in any order. Arranging 15 things in any order gives 15! = 1,307,674,368,000 possible paths. But that counts all the moves as being distinct, when actually the 10 right moves are indistinguishable, as are the 5 down moves, so we need to divide by the number of ways that they can be arranged. That gives us:" + "**Method 1: Count all permutations and divide by repetitions:** Any path on this grid must consist of 10 right and 5 down moves, but they can appear in any order. Arranging 15 things in any order gives 15! = 1,307,674,368,000 possible paths. But that counts all the moves as being distinct, when actually the 10 right moves are indistinguishable, as are the 5 down moves, so we need to divide by the number of ways that they can be arranged. That gives us:" ] }, { "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": false - }, + "execution_count": 52, + "metadata": {}, "outputs": [ { "data": { @@ -1162,7 +1596,7 @@ "3003" ] }, - "execution_count": 36, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -1181,10 +1615,8 @@ }, { "cell_type": "code", - "execution_count": 37, - "metadata": { - "collapsed": false - }, + "execution_count": 53, + "metadata": {}, "outputs": [ { "data": { @@ -1192,7 +1624,7 @@ "3003" ] }, - "execution_count": 37, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1207,16 +1639,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Method 3: Write a program to count the paths:** The function `calculate_paths(start, goal)` counts the number of paths from the start location to the goal location, where a location is an `(x, y)` pair of integers.\n", - "In general, the number of paths to the goal is the number of paths to the location just to the left of the goal, plus the number of paths to the location just above the goal. But there are two special cases: there is only one path (the empty path) when the start is equal to the goal, and there are zero paths when the goal is an illegal destination (one with a negative coordinate)." + "**Method 3: Write a program to count the paths:** The function `count_paths(start, goal)` counts the number of paths from the start location to the goal location, where a location is an `(x, y)` pair of integers.\n", + "In general, the number of paths to the goal is the number of paths to the location just to the left of the goal, plus the number of paths to the location just above the goal. But there are two special cases: there is only one path (the empty path) when the start is equal to the goal, and there are zero paths when the goal is an invalid destination (one with a negative coordinate)." ] }, { "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": false - }, + "execution_count": 54, + "metadata": {}, "outputs": [ { "data": { @@ -1224,37 +1654,35 @@ "3003" ] }, - "execution_count": 38, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@lru_cache(None)\n", - "def calculate_paths(start=(0, 0), goal=(5, 10)):\n", - " \"Number of paths to goal, using only 'right' and 'down' moves.\"\n", + "def count_paths(start=(0, 0), goal=(5, 10)) -> int:\n", + " \"\"\"Number of paths to goal, using only 'right' and 'down' moves.\"\"\"\n", " (x, y) = goal\n", " return (1 if goal == start else\n", " 0 if x < 0 or y < 0 else\n", - " calculate_paths(start, (x - 1, y)) + \n", - " calculate_paths(start, (x, y - 1)))\n", + " count_paths(start, (x - 1, y)) + \n", + " count_paths(start, (x, y - 1)))\n", " \n", - "calculate_paths()" + "count_paths()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Even though `calculate_paths` is slower than the `choose` calculation, it can still handle reasonably large grids:" + "Even though `count_paths` is slower than the `choose` calculation, it can still handle reasonably large grids:" ] }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": false - }, + "execution_count": 55, + "metadata": {}, "outputs": [ { "data": { @@ -1262,45 +1690,43 @@ "90548514656103281165404177077484163874504589675413336841320" ] }, - "execution_count": 39, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N = 100\n", - "\n", - "assert calculate_paths(goal=(N, N)) == choose(2 * N, N)\n", - "\n", - "calculate_paths(goal=(N, N))" + "assert count_paths(goal=(N, N)) == choose(2 * N, N)\n", + "count_paths(goal=(N, N))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Why bother with the recursive function `calculate_paths` when the `choose` formula works so well? Good question. One reason is that the two different approaches validate each other by giving the same answer. Another reason is that we can modify `calculate_paths` to handle things that are hard to do with just the formula. For example, what if we have a grid with some obstacles in it? I'll define a `Grid` constructor, which adopts the convention that the input is a string of rows, where a `'.'` character within a row is a passable square, and all other (non-whitespace) characters are impassible barriers. Then `calculate_grid_paths` finds the number of paths on a grid from start to goal (by default, from upper left to lower right):" + "Why bother with the recursive function `count_paths` when the `choose` formula works so well? Good question. One reason is **checking**: the two different approaches validate each other by giving the same answer. Another reason is that we can modify `count_paths` to handle things that are hard to do with just the formula. For example, what if we have a grid with some obstacles in it? I'll define a `Grid` constructor, which adopts the convention that the input is a string of rows, where a `'.'` character within a row is a passable square, and all other (non-whitespace) characters are impassible barriers. Then `count_grid_paths` finds the number of paths on a grid from start to goal (by default, from upper left to lower right):" ] }, { "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": true - }, + "execution_count": 56, + "metadata": {}, "outputs": [], "source": [ "def Grid(text): return tuple(text.split())\n", "\n", + "passable = '.'\n", + "\n", "@lru_cache(None)\n", - "def calculate_grid_paths(grid, start=(0, 0), goal=None):\n", - " \"Number of paths from start to goal on grid, using only 'right' and 'down' moves.\"\n", + "def count_grid_paths(grid, start=(0, 0), goal=None) -> int:\n", + " \"\"\"Number of paths from start to goal on grid, using only 'right' and 'down' moves.\"\"\"\n", " if goal is None: goal = (len(grid[-1]) - 1, len(grid) - 1) # bottom right\n", " (x, y) = goal\n", " return (1 if goal == start else\n", - " 0 if x < 0 or y < 0 or grid[y][x] != '.' else\n", - " calculate_grid_paths(grid, start, (x - 1, y)) + \n", - " calculate_grid_paths(grid, start, (x, y - 1)))" + " 0 if x < 0 or y < 0 or grid[y][x] != passable else\n", + " count_grid_paths(grid, start, (x - 1, y)) + \n", + " count_grid_paths(grid, start, (x, y - 1)))" ] }, { @@ -1312,10 +1738,8 @@ }, { "cell_type": "code", - "execution_count": 41, - "metadata": { - "collapsed": false - }, + "execution_count": 57, + "metadata": {}, "outputs": [ { "data": { @@ -1323,13 +1747,13 @@ "3003" ] }, - "execution_count": 41, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_grid_paths(Grid(\"\"\"\n", + "count_grid_paths(Grid(\"\"\"\n", "...........\n", "...........\n", "...........\n", @@ -1348,10 +1772,8 @@ }, { "cell_type": "code", - "execution_count": 42, - "metadata": { - "collapsed": false - }, + "execution_count": 58, + "metadata": {}, "outputs": [ { "data": { @@ -1359,13 +1781,13 @@ "2" ] }, - "execution_count": 42, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_grid_paths(Grid(\"\"\"\n", + "count_grid_paths(Grid(\"\"\"\n", "...........\n", ".........|.\n", ".........|.\n", @@ -1384,29 +1806,27 @@ }, { "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": false - }, + "execution_count": 59, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "167" + "122" ] }, - "execution_count": 43, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_grid_paths(Grid(\"\"\"\n", + "count_grid_paths(Grid(\"\"\"\n", "...........\n", ".........|.\n", ".........|.\n", ".........|.\n", - ".-------.+.\n", + ".------.-+.\n", "...........\n", "\"\"\"))" ] @@ -1420,24 +1840,22 @@ }, { "cell_type": "code", - "execution_count": 44, - "metadata": { - "collapsed": false - }, + "execution_count": 60, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "626386545674738" + "627084695807418" ] }, - "execution_count": 44, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_grid_paths(Grid(\"\"\"\n", + "count_grid_paths(Grid(\"\"\"\n", "....................................................................................................\n", "...................................NK0OkdddolcccccccccclloddxkO0XN..................................\n", "............................X0kdlc:cccccclodxllxxxkkxdloddolccccccccodkKN...........................\n", @@ -1456,21 +1874,19 @@ "...........XoX:xcX.........o.XXXXXXNk:X,kNNO:..........Xl0NKoX'oK.XXXXXXX:.........'xk;,k...........\n", "...........X.k;'lo;X.......l.XXXXXXXX.XXXXXXNxX.......,O.XXX.XNXXXXXXXXXK,.......'oxc'cK............\n", ".............XNx;,:lc,.....Xd.XXXXXXXXXXXXXXX.O'.....cXXXXXXXXXXXXXXXXXX:.....Xcoo:,cO..............\n", - "...............XNOl;;:c:;X..XlXXXXXXXXXXXXXXXXX0,..XoNXXXXXXXXXXXXXXX.O,..X;c.lc;:dK................\n", - "..................XNkl:;;:::::oXXXXXXXXXXXXXXXXX0:'oNXXXXXXXXXXXXXXXNkc:cccc:..:d0..................\n", - "......................NKko:;;;:lxOKX.XXXXXXXXXXXXNN.XXXXXXXXXXX..X0Odc::::cdOX......................\n", - "...........................N0kdl:;;:;;:clodxxkkkkOOOOkkxxddolc::::;:cldOK...........................\n", - "..................................XKOkxdolcc:;;::;;:::;::cllodxk0KN.................................\n", + "...............XNOl;;:c:;X..XlXXXXXXXXXXXXXXXXX0,...oNXXXXXXXXXXXXXXX.O,..X;c.lc;:dK................\n", + "..................XNkl:;;:.:::oXXXXXXXXXXXXXXXXX0:'.NXXXXXXXXXXXXXXXNkc:cccc:..:d0..................\n", + "......................NKko.;;;:lxOKX.XXXXXXXXXXXXNN.XXXXXXXXXXX..X0Odc::::cdOX......................\n", + "...........................N0kdl:;;:;;:clodxxkkkkOO.Okkxxddolc::::;:cldOK...........................\n", + "..................................XKOkxdolcc:;;::;;.::;::cllodxk0KN.................................\n", "....................................................................................................\n", - "\"\"\"))" + "\"\"\")) " ] }, { "cell_type": "code", - "execution_count": 45, - "metadata": { - "collapsed": false - }, + "execution_count": 61, + "metadata": {}, "outputs": [ { "data": { @@ -1478,13 +1894,13 @@ "11468451846417028993973305727890751485" ] }, - "execution_count": 45, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_grid_paths(Grid(r\"\"\"\n", + "count_grid_paths(Grid(r\"\"\"\n", ".....................................................................................................\n", ".................WXK0kxdd.oooooooooodxOXW............................................................\n", "..........W0xdoooooooodxk.00KKKKK00OxdoolokXW........................................................\n", @@ -1554,19 +1970,287 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Problem 7: Counting Positions in Fischerandom Chess\n", + "# Problem: Paths in a 2 x *n* Grid\n", "\n", - "> In this [variant](https://en.wikipedia.org/wiki/Chess960) of chess, the pieces are set up in a random but restricted fashion. The pawns are in their regular positions, and the major white pieces are placed randomly on the first rank, with two restrictions: the bishops must be placed on opposite-color squares, and the king must be placed between the rooks. The black pieces are set up to mirror the white pieces. How many starting positions are there?\n", + "Nicolas Schank proposes this problem:\n", "\n", - "We can answer by generating all distinct permutations of the eight pieces and quantifying (counting) the number of permutations that are legal:" + "> How many ways can you arrange the integers 1 through 2*n* in a 2 x *n* grid such that any two consecutive numbers are placed into squares that share a side?\n", + "\n", + "Another way of stating the problem is: how many paths are there that visit every square in 2 x *n* grid once, moving from a square to any of its orthogonal neighbors. (The integers 1 is then the first square in the path, 2 the second, and so on.)\n", + "\n", + "The **brute force enumeration** strategy would be to generate all (2*n*)! permutations of the integers and check if they form a valid path. That should work fine up to *n* = 6, but not much beyond that.\n", + "\n", + "Therefore I'll go to the **incremental enumeration strategy**, in which I start with paths of length 1 and extend them one square at a time, checking for validity at each step, until we find all the paths that reach all 2*n* squares. (This is not an **abstract** strategy: these are individual paths, not summaries of them.)\n", + "\n", + "I'll describe a `Path` with three components, `Path(end, n, squares)`:\n", + " - `end`: the `(x, y)` coordinates of the square that the path ends in.\n", + " - `n`: the width of the grid. (This is the same for every path in a problem instance, but I had to store it somewhere.)\n", + " - `squares`: a dict of `{(x, y): i}` entries giving the order of the squares visited.\n", + " \n", + "The approach then is that we start with one-square paths of the form `Path(s, n, {s: 1})` for every square `s` in the grid. Then we `iterate` calling `extend_paths` until we have all the complete paths. A path is extended by placing the integer `len(squares) + 1` in any square that neighbors `path.end` and does not already appear in `path.squares`." ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "Path = namedtuple('Path', 'end, n, squares')\n", + "\n", + "def incremental_count_paths(n) -> [Path]:\n", + " \"\"\"Extend every path as far as possible and return the ones of length 2*n\"\"\"\n", + " grid = product(range(n), (0, 1))\n", + " paths = [Path(s, n, {s: 1}) for s in grid]\n", + " return iterate(extend_paths, paths, 2 * n - 1)\n", + "\n", + "def extend_paths(paths) -> [Path]:\n", + " \"\"\"Return a list of paths that validly extend these paths by one square.\"\"\"\n", + " return [Path(end2, n, {end2: len(squares) + 1, **squares})\n", + " for (end, n, squares) in paths\n", + " for end2 in neighbors(n, *end) if end2 not in squares]\n", + "\n", + "def neighbors(n, x, y):\n", + " \"\"\"The squares that neighbor `(x, y)` in a nx2 grid.\"\"\"\n", + " if x < n-1: yield (x + 1, y)\n", + " if x > 0: yield (x - 1, y)\n", + " yield (x, 1 - y)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Path(end=(0, 1), n=2, squares={(0, 1): 4, (1, 1): 3, (1, 0): 2, (0, 0): 1}),\n", + " Path(end=(1, 0), n=2, squares={(1, 0): 4, (1, 1): 3, (0, 1): 2, (0, 0): 1}),\n", + " Path(end=(0, 0), n=2, squares={(0, 0): 4, (1, 0): 3, (1, 1): 2, (0, 1): 1}),\n", + " Path(end=(1, 1), n=2, squares={(1, 1): 4, (1, 0): 3, (0, 0): 2, (0, 1): 1}),\n", + " Path(end=(1, 1), n=2, squares={(1, 1): 4, (0, 1): 3, (0, 0): 2, (1, 0): 1}),\n", + " Path(end=(0, 0), n=2, squares={(0, 0): 4, (0, 1): 3, (1, 1): 2, (1, 0): 1}),\n", + " Path(end=(1, 0), n=2, squares={(1, 0): 4, (0, 0): 3, (0, 1): 2, (1, 1): 1}),\n", + " Path(end=(0, 1), n=2, squares={(0, 1): 4, (0, 0): 3, (1, 0): 2, (1, 1): 1})]" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "incremental_count_paths(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try to get a better understanding by visualizing the paths:" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [], + "source": [ + "def show_paths(paths, cols=4):\n", + " \"\"\"Plot all the paths in a matrix of subplots.\"\"\"\n", + " n = paths[0].n\n", + " P = len(paths)\n", + " fig, axs = plt.subplots(P // cols, cols, figsize=(14, 2 * n))\n", + " for y in range(P // cols):\n", + " for x in range(cols):\n", + " if paths:\n", + " path = paths.pop()\n", + " _, X, Y = zip(*(sorted((i, x, y) for (x, y), i in path.squares.items())))\n", + " axs[y, x].axis('off')\n", + " axs[y, x].plot(X, Y, 's-', clip_on=False)\n", + " axs[y, x].plot(X[:1], Y[:1], 'rs', clip_on=False)\n", + " fig.tight_layout(pad=3.0)\n", + " fig.suptitle(f'{P} Paths for a 2x{n} Grid:')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 65, "metadata": { - "collapsed": false + "scrolled": false }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for n in (2, 3, 4, 5):\n", + " show_paths(incremental_count_paths(n))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also create a table of number of paths as a function of `n`:" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: 2,\n", + " 2: 8,\n", + " 3: 16,\n", + " 4: 28,\n", + " 5: 44,\n", + " 6: 64,\n", + " 7: 88,\n", + " 8: 116,\n", + " 9: 148,\n", + " 10: 184,\n", + " 11: 224,\n", + " 12: 268}" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{n: len(incremental_count_paths(n)) for n in range(1, 13)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The visualization was interesting, and the number of valid paths makes it clear that this is not growing too quickly; probably polynomial rather than exponential. But I have no clue about a general formula for *n*.\n", + "\n", + "I'll try the **standing on shoulders** approach. I'll search for the first few elements of the sequence,\n", + "[\"2, 8, 16, 28, 44, 64\"](https://www.google.com/search?q=%222%2C+8%2C+16%2C+28%2C+44%2C+64%22), and see if anyone has reported on them. It turns out the [first search result](https://oeis.org/search?q=2%2C+8%2C+16%2C+28%2C+44%2C+64&language=english&go=Search) is from the online encyclopedia of integer sequences (a famous source for this kind of knowledge) for a sequence described as \"Number of (directed) Hamiltonian paths in the n-ladder graph.\" I know that a Hamiltonian path is a path that visits each vertex once, so that sounds right, and I had never heard the phrase \"n-ladder graph,\" but it makes sense that it is a 2 x *n* grid. So it looks like we're in the right place. The page gives this **calculation** formula:" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_paths(n): return 2 if n == 1 else 2 * (n ** 2 - n + 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "all(calculate_paths(n) == len(incremental_count_paths(n)) for n in range(1, 13))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our work here is done." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Counting Positions in Fischerandom Chess\n", + "\n", + "> In this [variant](https://en.wikipedia.org/wiki/Chess960) of chess, the pieces are set up in a random but restricted fashion. The pawns are in their regular positions, and the major white pieces are placed randomly on the first rank, with two restrictions: the bishops must be placed on opposite-color squares, and the king must be placed between the rooks. The black pieces are set up to mirror the white pieces. How many starting positions are there?\n", + "\n", + "We can answer by **enumerate and test**: generate all *distinct* permutations of the pieces and count the number that are valid:" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [], + "source": [ + "def valid_position(pieces) -> bool:\n", + " \"\"\"Valid if bishops are on different colors, and king is between rooks.\"\"\"\n", + " pieces = ''.join(pieces) # make `pieces` be a string (e.g. 'RNKBRQBN')\n", + " B, R, K = map(pieces.index, 'BRK')\n", + " b, r = map(pieces.rindex, 'BR')\n", + " return (color(B) != color(b)) and (r < K < R or R < K < r)\n", + "\n", + "def color(square): return 'BW'[square % 2]" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, "outputs": [ { "data": { @@ -1574,339 +2258,1625 @@ "960" ] }, - "execution_count": 46, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from statistics import median\n", - "\n", - "def legal_position(pieces):\n", - " \"Legal if bishops are on different colors, and king is between rooks.\"\n", - " B, R, K = map(pieces.index, 'BRK')\n", - " b, r = map(cat(pieces).rindex, 'BR')\n", - " return (B % 2 != b % 2) and R < K < r or r < K < R\n", - "\n", - "quantify(set(permutations('RNBKQBNR')), legal_position)" + "quantify(set(permutations('RNBKQBNR')), valid_position)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "[*Note:* initially I wrote `pieces.rindex` instead of `cat(pieces).rindex`, because I forgot that while tuples, lists and strings all have an `index` method, only strings have `rindex`. How annoying! In Ruby, both strings and arrays have `index` and `rindex`. In Java and Javascript, both strings and lists/arrays have both `indexOf` and `lastIndexOf`. What's wrong with Python?]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Problem 8: Counting Change\n", + "(*Note:* initially my program failed because I forgot that while tuples, lists and strings all have an `index` method, only strings have `rindex`. How annoying! I had to fix the problem by adding `pieces = ''.join(pieces)`. In Ruby, both strings and arrays have `index` and `rindex`. In Julia, both stringsss and arrays have `findfirst` and `findlast`. In Java and Javascript, both strings and lists/arrays have both `indexOf` and `lastIndexOf`. What's wrong with Python? )\n", "\n", - "> How many ways are there to select coins that add up to a specified amount of money? For example, to make 10 cents with an unlimited number of coins of denomination 10, 5, and 1 cents, there are four ways: {10, 5+5, 5+1+1+1+1+1, 1+1+1+1+1+1+1+1+1+1}. \n", - "\n", - "For this problem there is no sense of advanccing from $k$ to $k$+1; instead we will need a recursive breakdown. Here are the cases:\n", - "- There is one way to add up to zero cents (with no coins).\n", - "- It is not possible to add up to a negative amount (because there are no negative coins).\n", - "- It is not possible to add up to a positive amount if you don't have any coin denominations to do it.\n", - "- In the general case, you should add up the number of ways you can make change by using one coin of the first denomination, plus the number of ways you can do it by skipping the first denomination. If you use one coin of a denomination you are free to use another one, but once you skip a denomination, you can't go back to it later. That way, assuming we are looking at the largest denominations first, we will count 10+1, but we will not also count 1+10, which is as it should be." + "We could also do this by **calculation**. Let's handle the bishops first. The first bishop can go on any of the 8 squares, but then the second bishop has to go on an opposite color, so that's 4 choices. But then we divide by 2! = 2 because the two bishops are indistinguishable. Next, place the other pieces in the 6 remaining squares, for 6! possibilities, but divide by 2! because the knights are indistinguishable, and divide by 3! because, out of the 3! ways of ordering R-K-R left-to-right, only 2 of them are valid, but the 2 cancels out because the rooks are indistinguishable." ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "960.0" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(8 * 4 / factorial(2)) * factorial(6) / (factorial(2) * factorial(3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Counting Change\n", + "\n", + "> How many ways are there to select coins that add up to a specified amount of money? For example, to make 10 cents change with 10, 5, and 1 cent coins, there are four ways: `{10, 5+5, 5+1+1+1+1+1, 1+1+1+1+1+1+1+1+1+1}`. \n", + "\n", + "This is a well-known problem with a [Wikipedia page](https://en.wikipedia.org/wiki/Change-making_problem). But we'll tackle it in our own way. To start, I will use the term **mint** to describe a set of coin denominations. (I could have used **denominations**, but \"mint\" is shorter, and I can say \"mints\" to refer to several sets, but I can't say \"denominationses.\") The US mint produces coins in the following denominations:" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "mint = (100, 50, 25, 10, 5, 1) # Denominations of coins in US" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Conceptually a mint is a set, but the counting will be more efficient if the mint is ordered, with the largest values first.\n", + "\n", + "For this problem we will take a recursive **divide and conquer** approach with **remembering**. `count_change(amount, mint)` says how many ways there are to add up to `amount` using coins in `mint`. For example, `count_change(10, (10, 5, 1))` is 4. We analyze `count_change` as follows:\n", + "- There are three simple cases where we can answer immediately without having to divide the input:\n", + " - If the amount is zero cents there is one way to add up to the amount: with no coins.\n", + " - If the amount is negative, there are no ways.\n", + " - If the amount is positive but there are no denominations in the mint then there are no ways.\n", + "- Otherwise, we **divide** the possibilities into two parts and **conquer** by adding up the numbers from each part:\n", + " - Part 1: Use a coin of the first denomination in the mint. Figure out how many ways to make the rest of the amount with the mint.\n", + " - Part 2: Skip the first denomination in the mint. Figure out how many ways to make the whole amount without the denomination." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [], + "source": [ + "@lru_cache(None)\n", + "def count_change(amount, mint=mint) -> int:\n", + " \"\"\"The number of ways of adding up to `amount`, using coins from `mint`.\"\"\"\n", + " return (1 if amount == 0 else\n", + " 0 if amount < 0 or not mint else\n", + " count_change(amount - mint[0], mint) + \n", + " count_change(amount, mint[1:])) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can count the ways to make change for various amounts:" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "count_change(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "count_change(25)" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "252" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "count_change(99)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How many different piles of coins total up to $1000?" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13398445413854501" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "count_change(10**5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Aside: Recursion and @lru_cache\n", + "\n", + "*Quiz Question*: Wait a minute! Why doesn't `count_change(10**5)` raise a `RecursionError`? Doesn't `count_change` have to follow a chain of 100,000 recursive calls to handle the case where 100,000 1's total up to the amount? And isn't 100,000 larger than `sys.getrecursionlimit()`?\n", + " \n", + "*Quiz Answer*: We would indeed get a `RecursionError` if any of the following were true:\n", + "- The `@lru_cache` decorator were not used on `count_change`.\n", + "- We called `count_change(10**6)` instead of `count_change(10**5)`.\n", + "- The `mint` was ordered with the `1` first, not the `100`.\n", + "- The order of the two recursive calls to `count_change` were reversed. \n", + "\n", + "As it is, `count_change` fills the cache in such a way that it avoids too many recursive calls. To see what's happening, I'll create a plot of the call depth (on the y axis) for each successive recursive call to `count_change` (on the x-axis) in the execution of `count_change(10**5)`:" + ] + }, + { + "cell_type": "code", + "execution_count": 78, "metadata": { - "collapsed": true + "scrolled": false }, "outputs": [], "source": [ "@lru_cache(None)\n", - "def calculate_change(amount, denominations=(100, 50, 25, 10, 5, 1)):\n", - " return (1 if amount == 0 else\n", - " 0 if amount < 0 or not denominations else\n", - " calculate_change(amount - denominations[0], denominations) + \n", - " calculate_change(amount, denominations[1:]))" + "def count_change_with_depths(amount, mint=mint) -> int:\n", + " \"\"\"The number of ways of adding up to `amount`, using coins from `mint`.\n", + " This version appends call depths to `plot_depths.depths`.\"\"\"\n", + " global depth, depths\n", + " depth += 1\n", + " depths.append(depth)\n", + " result = (1 if amount == 0 else\n", + " 0 if amount < 0 or not mint else\n", + " count_change_with_depths(amount - mint[0], mint) + \n", + " count_change_with_depths(amount, mint[1:]))\n", + " depth -= 1\n", + " return result\n", + "\n", + "def plot_depths(amount, mint=mint, show=slice(None)):\n", + " \"\"\"Plot the call depths for `count_change(amount, mint)`.\"\"\"\n", + " global depth, depths\n", + " depth, depths = 0, []\n", + " count_change_with_depths.cache_clear()\n", + " count_change_with_depths(amount, mint)\n", + " plt.figure(figsize=(12, 6))\n", + " plt.xlabel('Call Number'); plt.ylabel('Depth')\n", + " X, Y = range(1, len(depths) + 1), depths\n", + " plt.plot(X[show], Y[show], '.-')\n", + " plt.grid(True); plt.gca().invert_yaxis()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For example:" + "(Note: this would be cleaner if done as a decorator to track depths, and with `depth` and `depths` being attributes rather than global variables.)" ] }, { "cell_type": "code", - "execution_count": 48, - "metadata": { - "collapsed": false - }, + "execution_count": 79, + "metadata": {}, "outputs": [ { "data": { + "image/png": "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\n", "text/plain": [ - "4" + "
" ] }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" } ], "source": [ - "calculate_change(11)" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "293" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_change(100)" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "139599978000" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_change(9999)" + "plot_depths(10**5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Problem 8b: Limited Change\n", - "\n", - "> The above assumed that you had a limitless supply of each denomination. What if you don't? \n", - "\n", - "I'll define `calculate_limited_change`, where, instead of specifying denominations, you specify actual coins, repeating the ones you have more than one of. We use the same strategy, and if you skip a denomination, you can never use another coin of the same denomination. " + "It looks like we first do a little over 1000 levels of recursion, then start popping the stack to return to the top level. But we can't really see from this plot how it happens; let's zoom in on the key part of the graph:" ] }, { "cell_type": "code", - "execution_count": 51, - "metadata": { - "collapsed": false - }, + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtoAAAFzCAYAAAAAFa6IAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzde3hb13nn++8CCN5JEYDupEQRjizbsS3blEUkbVKlSdymTZtM2jR10onbiZPOaWae00lnnied6fQ6c5pOm55Opj5p7TSJ0zrudZLYnkwcx4niaSLKNp34fpFEiRJlXUnwApAECGCdP4BNQRIvIAlg703+Ps/Dh+QmSK699sbeLxbe9S5jrUVERERERCor4HYDRERERETWIgXaIiIiIiJVoEBbRERERKQKFGiLiIiIiFSBAm0RERERkSpQoC0iIiIiUgV1bjegWjZu3Gh37drldjPmlUqlaGlpcbsZ64b6u/bU57Wl/q4t9Xdtqb9rT32+PAMDAxettZvm+9maDbR37drF008/7XYz5nXw4EEOHDjgdjPWDfV37anPa0v9XVvq79pSf9ee+nx5jDFDC/1MqSMiIiIiIlWgQFtEREREpAoUaIuIiIiIVIECbRERERGRKlCgLSIiIiJSBQq0RURERESqQIG2iIiIiEgVKNAWEREREakCBdoiIiIiIlXgSqBtjPm/jTEvGGNeNMb8enHbXmPMIWPM88aYh40x7cXtIWPM/cXtLxtjftONNouIiIiILEfNA21jzI3AR4H9wF7g3caY3cDngE9aa28CvgL8h+KvvB9oKG7vBX7VGLOr1u0ux8BQgnu+c5SBoYTbTRERERERl9W58D+vB/qttVMAxpjvAv8C2AM8UXzMY8CjwH8GLNBijKkDmoAMMFHrRi9lYCjBB+/rZzaXp74uwAN3x+ntDrvdLBERERFxibHW1vYfGnM98DXgTcA08DjwNIXR6j+y1n7NGPMJ4PestW3GmBDw18DbgWbg31lr713gb38M+BjAli1bev/2b/+26vvjeORYhn88MgsU3iZ43+4Q776mft7HJpNJWltba9a29U79XXvq89pSf9eW+ru21N+1pz5fnre97W0D1tp98/2s5iPa1tqXjTF/RGHUOgk8C2SBfwV8xhjz28BDFEauoZBikgO2A2Hg/xhjvmWtHZzn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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot_depths(10**5, show=slice(997, 1130))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that right at call number 1000 is the first time when the depth does not increase; it goes sideways for one step. Then we recurse to a maximum depth of 1014, and then gradually start zig-zagging back to the top level. We can figure out why this happens:\n", + "- First there are 1000 consecutive calls to `count_change_depths(amount - 100, mint)`. We can see there is a blue dot right at the (1000 calls, 1000 depth) grid point.\n", + "- The last of these calls is a call to `count_change_depths(0, mint)`, which returns without a recursive call, giving us the first sideways step (at call number 1001-1002, depth 1001).\n", + "- Call 1002 is the first recursive call to `count_change_depths(amount, mint[1:])` (this time with `amount=100`).\n", + "- We eventually fill in the cache entries for all amounts below 100, without ever going below depth 1014.\n", + "- We start returning up the stack: a zig up.\n", + "- Eventually we return and move on to a recursive call of `count_change_depths(200, mint[1:])`. \n", + "- To fill in the cache entries for 200 to 100: a zig down, but never as far down as 2014.\n", + "- We alternate returning up the stack, and going deeper to fill in entries for the next 100 amounts." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The pattern is easier to see with a limited mint of three coins: `(100, 10, 1)`:" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot_depths(10**5, mint=(100, 10, 1), show=slice(988, 3314))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each parallelogram corresponds to another 100 amounts being filled in. The depth never goes below 1021, and the parallelograms are gradually making their way up from the depths to the surface." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Variant Problem: Show Change\n", + "\n", + "Instead of *counting* how many ways there are to make change, we could *show* the actual coins in each way. \n", + "I'll use the term **purse** for a collection of coins, because it is a [**bag**](https://en.wikipedia.org/wiki/Multiset) of coins. I'll implement `Purse` as a `Counter` of `{denomination: count}` pairs. (A purse is different than a mint: a mint just lists the denominations; a purse lists the denominations and how many coins we have of each denomination.) For example, `Purse({10: 2, 1: 4})` means two 10-cent coins and four 1-cent coins, for a total of 24 cents. I'll give the `Purse` class two methods to add or subtract one or more coins of the same denomination; these methods produce a new `Purse` and do not modify the old one." + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [], + "source": [ + "class Purse(Counter): \n", + " \"\"\"A bag of coins (or of any objects, really).\"\"\"\n", + " def add(self, coin, n=1): return Purse(self + Counter({coin: n}))\n", + " def sub(self, coin, n=1): return Purse(self - Counter({coin: n}))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So `show_change` will return a list of Purses. The overall structure of the function is the same as `count_change`, but because of the additional complication of having to build up lists of purses for the results, I switch the body of the function from an *expression* to *statements*, to allow for the assignment of intermediate values to mnemonic variable names." + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, "outputs": [], "source": [ "@lru_cache(None)\n", - "def calculate_limited_change(amount, coins):\n", - " return (1 if amount == 0 else\n", - " 0 if amount < 0 or not coins else\n", - " calculate_limited_change(amount - coins[0], coins[1:]) + \n", - " calculate_limited_change(amount, tuple(c for c in coins if c != coins[0])))" + "def show_change(amount, mint=mint) -> [Purse]:\n", + " \"\"\"List all the purses that adds up to `amount`, using `mint`.\"\"\"\n", + " if amount == 0:\n", + " return [Purse()] \n", + " elif amount < 0 or not mint:\n", + " return []\n", + " else:\n", + " coin = mint[0]\n", + " use = show_change(amount - coin, mint)\n", + " skip = show_change(amount, mint[1:])\n", + " return [purse.add(coin) for purse in use] + skip" ] }, { "cell_type": "code", - "execution_count": 52, - "metadata": { - "collapsed": false - }, + "execution_count": 84, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "4" + "[Purse({1: 1, 10: 1}),\n", + " Purse({1: 1, 5: 2}),\n", + " Purse({1: 6, 5: 1}),\n", + " Purse({1: 11})]" ] }, - "execution_count": 52, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_limited_change(10, (10, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))" + "show_change(11)" ] }, { "cell_type": "code", - "execution_count": 53, - "metadata": { - "collapsed": false - }, + "execution_count": 85, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "4" + "[Purse({5: 1, 10: 1}),\n", + " Purse({1: 5, 10: 1}),\n", + " Purse({5: 3}),\n", + " Purse({1: 5, 5: 2}),\n", + " Purse({1: 10, 5: 1}),\n", + " Purse({1: 15})]" ] }, - "execution_count": 53, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_limited_change(10, (50, 25, 10, 10, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))" + "show_change(15)" ] }, { "cell_type": "code", - "execution_count": 54, - "metadata": { - "collapsed": false - }, + "execution_count": 86, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "1" + "[Purse({25: 1}),\n", + " Purse({5: 1, 10: 2}),\n", + " Purse({1: 5, 10: 2}),\n", + " Purse({5: 3, 10: 1}),\n", + " Purse({1: 5, 5: 2, 10: 1}),\n", + " Purse({1: 10, 5: 1, 10: 1}),\n", + " Purse({1: 15, 10: 1}),\n", + " Purse({5: 5}),\n", + " Purse({1: 5, 5: 4}),\n", + " Purse({1: 10, 5: 3}),\n", + " Purse({1: 15, 5: 2}),\n", + " Purse({1: 20, 5: 1}),\n", + " Purse({1: 25})]" ] }, - "execution_count": 54, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "calculate_limited_change(10, (10, 5, 1, 1, 1, 1))" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_limited_change(25, (25, 10, 10, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)) " - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "calculate_limited_change(25, (25, 10, 5, 5, 5, 5, 1, 1, 1, 1)) " + "show_change(25)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Problem 8c: Optimal Denominations\n", + "## Variant Problem: Show Limited Change\n", "\n", - "The *[July 20, 2018 Riddler](https://fivethirtyeight.com/features/damn-the-torpedoes-two-puzzles-ahead/)* poses this problem (which has a [Wikipedia](https://en.wikipedia.org/wiki/Change-making_problem) article and a [journal](https://cs.uwaterloo.ca/~shallit/Papers/change2.pdf) article):\n", + "> The above assumed that we had a limitless supply of coins of each denomination. What if we only have a limited number of coins in our purse?\n", "\n", - "> I was recently traveling in Europe and struck by the number of coins the euro uses. They have 2 euro, 1 euro, 50 cent, 20 cent, 10 cent, 5 cent, 2 cent and 1 cent coins. This got me thinking: If Riddler Nation needed to make change (anywhere from 0.01 to 0.99) and was establishing its own denomination, what values of coins would be ideal to yield the smallest number of coins in any transaction? When picking values, let’s say we’re ditching the Europeans and limiting our denomination to four different coin denominations — replacing the current common American ones of penny, nickel, dime and quarter. \n", - "\n", - "This is an optimization problem, not a counting problem, but it is related to the other coin/denomination problems here. Here's how I address the problem:\n", - "- The function `totalcoins(denominations)` will give the total number of coins (taken from those denominations) that are\n", - "required to make each amount of change from 1 to 99 cents (assuming optimal change choices).\n", - "- The function `mincoins(amount, denominations)` computes this optimal number of coins for a given amount, or returns infinity if the amount cannot be made.\n", - "- I know I'm going to need a 1 cent piece; otherwise I can't make 1 cent total.\n", - "- That leaves 3 coins that could be anywhere from 2 to 99 cents; let's try all combinations (even though it will take a minute or two). \n", - "- We'll report the candidate combination that has the minimum total number of coins.\n" + "I'll define `show_limited_change`, which, instead of takling a mint as argument, takes a purse with a specific number of coins of each denomination. We use the same strategy as `show_change`:" ] }, { "cell_type": "code", - "execution_count": 57, - "metadata": { - "collapsed": false - }, + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "def show_limited_change(amount, purse) -> [Counter]:\n", + " \"\"\"List all the ways of making change that adds up to `amount`, using `coins`.\"\"\"\n", + " if amount == 0:\n", + " return [Purse()] \n", + " elif amount < 0 or not purse:\n", + " return []\n", + " else:\n", + " coin = max(purse)\n", + " use = show_limited_change(amount - coin, purse.sub(coin, n=1))\n", + " skip = show_limited_change(amount, purse.sub(coin, n=purse[coin]))\n", + " return [purse.add(coin) for purse in use] + skip" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Purse({1: 1, 10: 1}),\n", + " Purse({1: 1, 5: 2}),\n", + " Purse({1: 6, 5: 1}),\n", + " Purse({1: 11})]" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_limited_change(11, Purse({10: 4, 5: 3, 1: 11}))" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Purse({1: 1, 10: 1})]" + ] + }, + "execution_count": 89, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_limited_change(11, Purse({10: 4, 5: 1, 1: 4}))" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Purse({25: 1})]" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_limited_change(25, Purse({25: 1, 10: 1, 5: 2, 1: 4})) " + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_limited_change(25, Purse({10: 12, 1: 4}))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Variant Problem: Optimal mint\n", + "\n", + "The [July 20, 2018 Riddler](https://fivethirtyeight.com/features/damn-the-torpedoes-two-puzzles-ahead/) poses this problem (slightly edited here):\n", + "\n", + "> If Riddler Nation needed to make change (anywhere from 0.01 to 0.99) and was establishing its own mint, what values of coins would be ideal to yield the smallest number of coins in an average transaction? You can assume that all amounts of change from 0.01 to 0.99 are equally likely. Let’s limit our mint to four different coin denominations. \n", + "\n", + "Technically this is an optimization problem, not a counting problem, but we'll answer it anyway. (It is an interesting problem that boasts at least one [journal article](https://cs.uwaterloo.ca/~shallit/Papers/change2.pdf).) Here's how I address the problem:\n", + "- The function `meancoins(mint)` will give the mean number of coins required to make each amount of change from 0 to 99 cents.\n", + "- The function `mincoins(amount, mint)` computes how many coins are needed for a given amount, or returns an absurdly large number (`maxsize`) if the amount cannot be made. (A mint that contains a `1` can make any amount.)\n", + "- The variable `mints` holds a list of possible four-coin mints, such as `(27, 13, 3, 1)`. I know that a 1 cent piece is required; otherwise I can't make an amount of 1 cent. That leaves 3 coins that could be anywhere from 2 to 99 cents; `mints` enumerate all the possible combinations." + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "152096" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@lru_cache(None)\n", + "def mincoins(amount, mint) -> int:\n", + " \"\"\"The minimum number of coins, taken from mint, that add to amount.\"\"\"\n", + " return (0 if amount == 0 else\n", + " maxsize if not mint or amount < min(mint) else\n", + " min(mincoins(amount, mint[1:]),\n", + " mincoins(amount - mint[0], mint) + 1))\n", + "\n", + "def meancoins(mint, minimizer=mincoins, amounts=range(100)) -> float: \n", + " \"\"\"The mean number of coins needed to make change for all the amounts.\"\"\"\n", + " return sum(minimizer(a, mint) for a in amounts) / len(amounts)\n", + "\n", + "mints = [(L, M, S, 1) for S, M, L in combinations(range(2, 100), 3)]\n", + "len(mints)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now I can sort the mints by `meancoins`:" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 1min 40s, sys: 5.93 s, total: 1min 46s\n", - "Wall time: 1min 55s\n" + "CPU times: user 32.6 s, sys: 1.83 s, total: 34.4 s\n", + "Wall time: 41.7 s\n" ] - }, - { - "data": { - "text/plain": [ - "(25, 18, 5, 1)" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "def totalcoins(denominations) -> int: \n", - " \"The total number of coins needed to make change for all amounts up to 99 cents.\"\n", - " return sum(mincoins(a, denominations) for a in range(1, 100))\n", - "\n", - "@lru_cache(None)\n", - "def mincoins(amount, denominations) -> int:\n", - " \"The minimum number of coins, taken from denominations, that add to amount.\"\n", - " return (0 if amount == 0 else\n", - " inf if not denominations or amount < min(denominations) else\n", - " min(mincoins(amount, denominations[1:]),\n", - " mincoins(amount - denominations[0], denominations) + 1))\n", - "\n", - "candidates = ((L, M, S, 1) for S, M, L in combinations(range(2, 100), 3))\n", - "\n", - "%time min(candidates, key=totalcoins) " + "%time mints.sort(key=meancoins)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Interesting! This is almost the US system of coins; we just need to trade in the dime for an 18 cent piece." + "And look at the top 10, along with the US system:" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [], + "source": [ + "topmints = mints[:10] + [(25, 10, 5, 1)]" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{(25, 18, 5, 1): 3.89,\n", + " (29, 18, 5, 1): 3.89,\n", + " (30, 18, 4, 1): 3.9,\n", + " (28, 17, 4, 1): 3.91,\n", + " (29, 19, 4, 1): 3.91,\n", + " (30, 19, 5, 1): 3.91,\n", + " (28, 21, 5, 1): 3.91,\n", + " (32, 19, 4, 1): 3.92,\n", + " (30, 23, 5, 1): 3.92,\n", + " (31, 14, 6, 1): 3.92,\n", + " (25, 10, 5, 1): 4.7}" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{mint: meancoins(mint) for mint in topmints}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Interesting! The mint on the top line, (25, 18, 5, 1), is almost the US system of coins; we just need to trade in the dime for an 18 cent piece. It takes an average of 3.89 coins to make any amount from 0 to 99 (as does the mint on the second line, `(29, 18, 5, 1)`). We could also consider trading in the quarter for a 29 or 30 cent piece. The US system, at 4.7 mean number of coins, is almost a full coin behind the best mint.\n", + "\n", + "However, I'm not sure that `meancoins` is the best measure of a mint system. For one thing, it can be mentally taxing to compute the minimum purse of coins for an amount. It is mentally easier to use a **greedy approach** which says: to make change, start with the largest coin available, and use as many of those as possible; then continue to the other coins in decreasing order. With this approach you never have to compare two possible options. \n", + "\n", + "I'll define `greedy_mincoins(amount, mint)` to say how many coins are needed to make `amount` from `mint` using the greedy aprroach, and `show_greedy_limited_mincoins(amount, purse)` to show the coins that can make up `amount`, drawing only from `purse`. " + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [], + "source": [ + "def greedy_mincoins(amount, mint) -> int: \n", + " \"\"\"The number of ways of adding up to `amount`, using coins from `mint`.\"\"\"\n", + " bank = Purse({d: 1000 for d in mint})\n", + " return total(show_greedy_limited_mincoins(amount, bank))\n", + "\n", + "def show_greedy_limited_mincoins(amount, purse) -> Purse:\n", + " \"\"\"Change, taken greedily from purse, that adds to amount.\"\"\"\n", + " change = Purse()\n", + " for coin in sorted(purse, reverse=True):\n", + " while coin <= amount:\n", + " amount -= coin\n", + " change[coin] += 1\n", + " purse = purse.sub(coin)\n", + " return change if amount == 0 else None\n", + "\n", + "def is_canonical(mint) -> bool:\n", + " \"\"\"Does this mint give the same results with `mincoins` and `greedy_mincoins`?\"\"\"\n", + " return same(lambda a: mincoins(a, mint), \n", + " lambda a: greedy_mincoins(a, mint), \n", + " range(100))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The greedy approach is not optimal for all amounts and mints. For example, to make the amount 30 with the mint `(25, 10, 1)` the greedy approach takes the 25, and then must add five 1-cent coins for a total of 6 coins. The optimal `mincoins` approach selects three 10-cent coins. A mint for which the greedy algorithm is optimal for all amounts is called a **canonical** system." + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "greedy_mincoins(30, (25, 10, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "greedy_mincoins(6, (4, 3, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Purse({25: 1, 1: 5})" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_greedy_limited_mincoins(30, Purse({25: 1, 10: 3, 1: 7}))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's compare the mean number of coins needed under the optimal and greedy approaches, and check which mints are canonical:" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{(25, 18, 5, 1): (3.89, 4.58, False),\n", + " (29, 18, 5, 1): (3.89, 4.45, False),\n", + " (30, 18, 4, 1): (3.9, 4.38, False),\n", + " (28, 17, 4, 1): (3.91, 4.44, False),\n", + " (29, 19, 4, 1): (3.91, 4.41, False),\n", + " (30, 19, 5, 1): (3.91, 4.48, False),\n", + " (28, 21, 5, 1): (3.91, 4.62, False),\n", + " (32, 19, 4, 1): (3.92, 4.41, False),\n", + " (30, 23, 5, 1): (3.92, 4.6, False),\n", + " (31, 14, 6, 1): (3.92, 4.45, False),\n", + " (25, 10, 5, 1): (4.7, 4.7, True)}" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{mint: (meancoins(mint, mincoins), meancoins(mint, greedy_mincoins), is_canonical(mint))\n", + " for mint in topmints}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now it looks like maybe `(30, 18, 4, 1)` is the best mint: it is only 0.01 behind the leader in optimal score, and it has the best greedy score.\n", + "\n", + "We also see that among the mints shown, only the US system, `(25, 10, 5, 1)` is canonical: it gets the same score under greedy and optimal approaches. However, even its optimal score, 4.7, is worse than the greedy score of all the mints above it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Variant: Mean Purse Size\n", + "\n", + "Here's another criteria for a mint system: I would like to not accumulate too many coins in my purse/pocket. Suppose I do a cash transaction in which I owe a certain amount of cents, `amount`. If I happen to have coins in my purse that add up to `amount`, I will pay with them (and end up with fewer coins). If I don't, I'll pay for the cents with a dollar bill, and I'll receive `100 - amount` in change back (and end up with more coins). (I won't allow the scenario where, say, I owe 24¢ and pay 25¢ and get 1¢ back.) Will some mints lead to accumulation of more coins than others? I'll do a random **simulation** to see:" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [], + "source": [ + "@lru_cache(None)\n", + "def purse_stats(mint, t=25000, seed=42):\n", + " \"\"\"The mean and standard deviation of the number of coins in a purse\n", + " after each of `t` random transactions.\"\"\"\n", + " random.seed(seed)\n", + " purse = Purse()\n", + " bank = Purse({c: 100 for c in mint})\n", + " sizes = []\n", + " for _ in range(t):\n", + " amount = random.randrange(1, 100)\n", + " pay = show_greedy_limited_mincoins(amount, purse)\n", + " if pay:\n", + " purse -= pay\n", + " else:\n", + " change = show_greedy_limited_mincoins(100 - amount, bank)\n", + " purse += change\n", + " sizes.append(total(purse))\n", + " return mean(sizes), stdev(sizes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I can compare various mints:" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(5.6928, 4.441767365800834)" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "purse_stats((25, 10, 5, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(6.47408, 4.9299959784987575)" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "purse_stats((25, 18, 5, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This says that the US system leaves me, on average, with fewer coins in my purse. But the standard deviation is large compared to the mean, so this may not be very reliable in the short run.\n", + "\n", + "One more thing I'm interested in is what is the *worst* amount for a mint: the amount that requires the most coins? And what are those coins?" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [], + "source": [ + "def worst_amount(mint):\n", + " \"\"\"What amount (and coins) requires the most number of coins for mint?\"\"\"\n", + " amount = max(range(100), key=lambda a: mincoins(a, mint)) # Worst amount\n", + " coins = min((list(c.elements()) for c in show_change(amount, mint)), key=len)\n", + " return amount, coins\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(94, [1, 1, 1, 1, 5, 10, 25, 50])" + ] + }, + "execution_count": 105, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "worst_amount(mint)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a report summarizing all we have learned about the various mints:" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [], + "source": [ + "def mint_report(mints):\n", + " print('Mint of Coins Mean Greedy Canon PurseSize Amount-requiring-most-coins')\n", + " for mint in mints:\n", + " m, g = meancoins(mint), meancoins(mint, greedy_mincoins)\n", + " mu, sd = purse_stats(mint)\n", + " a, coins = worst_amount(mint)\n", + " print(f'{mint} {m:.2f} {g:.2f} {m==g!s:5} {mu:4.1f} ± {sd:3.1f} {a:2}¢ {len(coins)}: {coins[::-1]}')" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mint of Coins Mean Greedy Canon PurseSize Amount-requiring-most-coins\n", + "(25, 18, 5, 1) 3.89 4.58 False 6.5 ± 4.9 14¢ 6: [5, 5, 1, 1, 1, 1]\n", + "(29, 18, 5, 1) 3.89 4.45 False 8.4 ± 6.5 14¢ 6: [5, 5, 1, 1, 1, 1]\n", + "(30, 18, 4, 1) 3.90 4.38 False 7.1 ± 5.7 15¢ 6: [4, 4, 4, 1, 1, 1]\n", + "(28, 17, 4, 1) 3.91 4.44 False 6.4 ± 5.0 99¢ 7: [28, 28, 17, 17, 4, 4, 1]\n", + "(29, 19, 4, 1) 3.91 4.41 False 7.7 ± 6.0 15¢ 6: [4, 4, 4, 1, 1, 1]\n", + "(30, 19, 5, 1) 3.91 4.48 False 6.1 ± 4.6 14¢ 6: [5, 5, 1, 1, 1, 1]\n", + "(28, 21, 5, 1) 3.91 4.62 False 7.6 ± 6.1 19¢ 7: [5, 5, 5, 1, 1, 1, 1]\n", + "(32, 19, 4, 1) 3.92 4.41 False 6.5 ± 5.2 15¢ 6: [4, 4, 4, 1, 1, 1]\n", + "(30, 23, 5, 1) 3.92 4.60 False 6.4 ± 4.9 19¢ 7: [5, 5, 5, 1, 1, 1, 1]\n", + "(31, 14, 6, 1) 3.92 4.45 False 6.8 ± 5.1 98¢ 7: [31, 31, 14, 14, 6, 1, 1]\n", + "(25, 10, 5, 1) 4.70 4.70 True 5.7 ± 4.4 94¢ 9: [25, 25, 25, 10, 5, 1, 1, 1, 1]\n" + ] + } + ], + "source": [ + "mint_report(topmints)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The US system (bottom row) has the advantage of being canonical, and of being natural for people with five fingers on a hand. But its mean number of coins needed is high, as is its maximum number of coins, 9 (to make 94¢). The `(25, 18, 5, 1)` mint has the best (tied) `mincoins` mean score, the best (tied) maximum-number-of-coins score, and pretty good greedy and purse-size scores. It might have been a better system overall, but not by enough of a margin to seriously consider a switch." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem: Drink Gift Cards\n", + "\n", + "[538 Riddler](https://fivethirtyeight.com/features/does-your-gift-card-still-have-free-drinks-on-it/) presents this problem:\n", + " \n", + "> Lucky you! You’ve won two gift cards, each loaded with 50 free drinks from your favorite coffee shop, Riddler Caffei-Nation. The cards look identical, and because you’re not one for record-keeping, you randomly pick one of the cards to pay with each time you get a drink. One day, the clerk tells you that the card you presented doesn’t have any drink credits left on it. How many free drinks can you expect are still available on the other card?\n", + "\n", + "Can I **enumerate** all sequences of choosing one card or the other? No: that would be (100 choose 50) ≅ 1029 sequences. But I can to use recursive **divide and conquer**: I'll define `other_card(a, b)` to return a probability distribution of the number of drinks remaining on the \"other\" card, when we start with two cards with `a` and `b` drinks remaining, respectively, and we use them until one card is exhausted. At every step, the function considers decrementing both `a` and `b`, with equal probability (1/2 each). \n", + "\n", + "I can define a probability distribution, `Dist`, as a subclass of `Counter` to which I add a method for multiplying by a scalar." + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [], + "source": [ + "class Dist(Counter):\n", + " \"\"\"A frequency distribution of {item: frequency}.\"\"\"\n", + " def __mul__(self, scalar): return Dist({x: scalar * self[x] for x in self})\n", + " __rmul__ = __mul__\n", + "\n", + "@lru_cache(None)\n", + "def other_card(a, b):\n", + " \"\"\"Probability distribution of drinks remaining on other card when one card runs out.\"\"\"\n", + " a, b = sorted((a, b)) # Ensure a <= b\n", + " return (Dist({b: 1}) if a == 0 else\n", + " Dist(1/2 * other_card(a - 1, b) + \n", + " 1/2 * other_card(a, b - 1)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If I have one free drink on each card and I use one, then the other card has one drink with probability 1.0:" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Dist({1: 1.0})" + ] + }, + "execution_count": 109, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "other_card(1, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If I start with two free drinks on each card and I use them randomly until one runs out, then it is equally likely that there are 1 or 2 left on the other card:" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Dist({2: 0.5, 1: 0.5})" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "other_card(2, 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's the full probability distribution for the original question:" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Dist({50: 1.7763568394002505e-15,\n", + " 49: 4.440892098500626e-14,\n", + " 48: 5.662137425588298e-13,\n", + " 47: 4.907185768843192e-12,\n", + " 46: 3.2510105718586146e-11,\n", + " 45: 1.755545708803652e-10,\n", + " 44: 8.046251165350071e-10,\n", + " 43: 3.2185004661400285e-09,\n", + " 42: 1.1465907910623852e-08,\n", + " 41: 3.6945703267565744e-08,\n", + " 40: 1.0898982463931894e-07,\n", + " 39: 2.9724497628905167e-07,\n", + " 38: 7.554976480680063e-07,\n", + " 37: 1.8015713146237074e-06,\n", + " 36: 4.053535457903342e-06,\n", + " 35: 8.647542310193795e-06,\n", + " 34: 1.7565320317581147e-05,\n", + " 33: 3.409738649883399e-05,\n", + " 32: 6.345902487282993e-05,\n", + " 31: 0.0001135582550355904,\n", + " 30: 0.00019588798993639344,\n", + " 29: 0.00032647998322732244,\n", + " 28: 0.0005268199729349975,\n", + " 27: 0.0008245877837243439,\n", + " 26: 0.0012540605877474397,\n", + " 25: 0.0018560096698662107,\n", + " 24: 0.0026769370238454962,\n", + " 23: 0.0037675409965232907,\n", + " 22: 0.005180368870219524,\n", + " 21: 0.006966702963398672,\n", + " 20: 0.009172825568474917,\n", + " 19: 0.011835903959322474,\n", + " 18: 0.014979815948517508,\n", + " 17: 0.01861128648149145,\n", + " 16: 0.022716717322996918,\n", + " 15: 0.027260060787596296,\n", + " 14: 0.03218201620757896,\n", + " 13: 0.03740072153853771,\n", + " 12: 0.04281398386648397,\n", + " 11: 0.04830295615705883,\n", + " 10: 0.053737038724727945,\n", + " 9: 0.05897967664909165,\n", + " 8: 0.06389464970318263,\n", + " 7: 0.0683524159615442,\n", + " 6: 0.07223607595935921,\n", + " 5: 0.07544656822421962,\n", + " 4: 0.0779067824054442,\n", + " 3: 0.07956437352045362,\n", + " 2: 0.08039316907795838,\n", + " 1: 0.08039316907795838})" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "other_card(50, 50)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can compute the expected value, `EV`, of this distribution:" + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "7.958923738717876" + ] + }, + "execution_count": 112, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def EV(P): \n", + " \"\"\"Expected value of a probability distribution.\"\"\"\n", + " return sum(b * P[b] for b in P)\n", + "\n", + "EV(other_card(50, 50))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So on average, we expect about 8 drinks left on the other card.\n", + "\n", + "What if we were given two different gift cards to begin with? Say a 25- and a 50-drink card?" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "25.008494650139617" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "EV(other_card(25, 50))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's interesting. The expectation is almost exactly 25 drinks remaining on the other card (which in almost all cases will be the card that originally had 50 drinks). That doesn't mean there will always be 25 left, or even a number close to that. We see below that the remaining drinks on the other card is in the range 20-30 about half the time:" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5148807410710244" + ] + }, + "execution_count": 114, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "P = other_card(25, 50)\n", + "sum(P[d] for d in range(20, 30))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can plot the probability distribution of `other_card(n, n)` for various values of `n`:" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def show_other_cards(ns):\n", + " X = list(range(1, max(ns) // 2 + 1))\n", + " for n in ns:\n", + " P = other_card(n, n)\n", + " Y = [P[b] for b in X]\n", + " plt.plot(X, Y, '.-', label=f'n = {n}; EV = {float(EV(P)):.2f}')\n", + " plt.grid(True)\n", + " plt.xlabel('Drinks Remaining'); plt.ylabel('Probability')\n", + " plt.legend()\n", + " \n", + "show_other_cards((20, 25, 30, 40, 50, 60, 75, 99))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Counting Multiplications in Matrix Multiplication\n", + "\n", + "> Given a sequence of matrices to be multiplied together, what is the minimum number of multiplications of the constituent numbers, out of all the possible bracketings of the sequence?\n", + "\n", + "See [Wikipedia's matrix multiplication](https://en.wikipedia.org/wiki/Matrix_multiplication) page for a refresher if needed, but we will explain everything here. A matrix is a two-dimensional grid of numbers. When we multiply two matrices, we do a lot of multiplications of the constituent numbers. In the diagram below we see that multiplying a matrix of dimensions $l × m$ by a $m × n$ matrix results in a $l × n$ matrix, $C$, where each element $C_{ij}$ is the dot product of two $m$ element vectors, for a total of $l × m × n$ multiplications of constituent numbers. (Forget about [Strassen](https://en.wikipedia.org/wiki/Strassen_algorithm) for now.)\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Matrix_multiplication_qtl1.svg/440px-Matrix_multiplication_qtl1.svg.png)\n", + "\n", + "$$\\sum_{k=1}^{m} A_{ik} × B_{kj} = C_{i,j}$$\n", + "\n", + "To multiply *three* matrices together, we could do either **(AB)C** or **A(BC)**; both give the same answer, but one might do fewer constituent multiplications. For a sequence of four matrices, there are five possible bracketings: **((AB)C)D, (A(BC))D, (AB)(CD), A((BC)D)**, or **A(B(CD))**. We want to find the bracketing with the fewest constituent multiplications.\n", + "\n", + "Here's how I start to think about it:\n", + "\n", + "- We don't need to represent the contents of the matrices, just the dimensions.\n", + "- `Matrix(c, m, n)` will represent a matrix of dimensions $m × n$ that requires $c$ constituent multiplications. I'll implement `Matrix` as a `namedtuple` to which I add a method for multiplication. (To be clear: it doesn't do matrix multiplication; it just computed the count of constituent multiplications and the dimensions of the product.)\n", + "- `M(m, n)` is a handy abbreviation for `Matrix(0, m, n)`\n", + "\n", + "Here is the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [], + "source": [ + "class Matrix(namedtuple('_', 'count, d1, d2')):\n", + " \"\"\"Contains the dimensions (d1, d2) and a count of the number of multiplies.\"\"\" \n", + " def __mul__(A, B):\n", + " assert A.d2 == B.d1\n", + " count = A.count + B.count + A.d1 * A.d2 * B.d2\n", + " return Matrix(count, A.d1, B.d2)\n", + "\n", + "def M(m, n): return Matrix(0, m, n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Some examples of use:" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=5000, d1=10, d2=5)" + ] + }, + "execution_count": 117, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A, B, C = M(10, 100), M(100, 5), M(5, 20)\n", + "\n", + "A * B" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=10000, d1=100, d2=20)" + ] + }, + "execution_count": 118, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "B * C" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=6000, d1=10, d2=20)" + ] + }, + "execution_count": 119, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(A * B) * C" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=30000, d1=10, d2=20)" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A * (B * C)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The bracketing **(AB)C** results in 6000 multiplications; five times less than **A(BC)**. Here's how to find the best product of a sequence of matrices:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `multbest(matrices)` will return a `Matrix` that is the product of `matrices` and has the minimum number of constituent multiplications.\n", + "- The **brute force enumeration** approach would be to try every possible bracketing. How many bracketings are there? It turns out the answer is again the [Catalan numbers](https://en.wikipedia.org/wiki/Catalan_number), so for 10 matrices there are only 4,862 possibilities; no problem. But for 25 matrices, there are 1,289,904,147,324 possibilities.\n", + "- We don't need to evaluate every bracketing. Consider splitting the sequence of matrices into two parts, *left* and *right*. We don't need to find every way of bracketing *left* and combine each of those with every way of bracketing *right*; we only need to find the one best way of bracketing *left* and combine it with the one best way of bracketing *right*. We do have to consider every way of splitting *left* and *right*, but there are only *O(n)* of those.\n", + "- So the algorithm for `multbest` will be a form of the **incremental enumeration** with **remembering** approach:\n", + " - For every way of splitting the sequence of matrices, recursively find the best matrix products for the *left* and *right* parts of the split, and multiply them to get a candidate.\n", + " - Out of those candidates, return the one with the minimum number of multiplications. (Since `Matrix` was defined as a namedtuple with the count as the first field, the `min` matrix is the one with the minimum count.)\n", + " - We use `@lru_cache` to stop the algorithm from repeating itself." + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [], + "source": [ + "@lru_cache(None)\n", + "def multbest(matrices):\n", + " \"\"\"Find the product of matrices that uses the least number of multiplications.\"\"\"\n", + " return (matrices[0] if len(matrices) == 1 else\n", + " min(multbest(left) * multbest(right) \n", + " for left, right in splits(matrices)))\n", + " \n", + "def splits(seq): return [(seq[:i], seq[i:]) for i in range(1, len(seq))]" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('A', 'BCDEF'),\n", + " ('AB', 'CDEF'),\n", + " ('ABC', 'DEF'),\n", + " ('ABCD', 'EF'),\n", + " ('ABCDE', 'F')]" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "splits(\"ABCDEF\")" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=6000, d1=10, d2=20)" + ] + }, + "execution_count": 123, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "multbest((A, B, C))" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=75350, d1=10, d2=20)" + ] + }, + "execution_count": 124, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "example = (A, B, C, M(20, 99), M(99, 10), M(10, 100), M(100, 80), M(80, 10), A, B, C)\n", + "\n", + "multbest(example)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see it takes 75,350 constituent multiplications to work out the matrix product of the sequence of eleven `example` matrices. Is that a lot or a little? We can compare this optimal result to the pessimal result:" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [], + "source": [ + "def multworst(matrices):\n", + " \"\"\"Find the product of matrices that uses the MOST number of multiplications.\"\"\"\n", + " return (matrices[0] if len(matrices) == 1 else\n", + " max(multworst(left) * multworst(right) \n", + " for left, right in splits(matrices)))" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Matrix(count=3407000, d1=10, d2=20)" + ] + }, + "execution_count": 126, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "multworst(example)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's 45 times more work! It seems worthwhile to take the optimal approach." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Thanks for making it all the way to the end of the notebook. I hope you've learned something about methods for counting things, and that you can apply them to your own problems." ] } ], @@ -1926,7 +3896,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.0" + "version": "3.7.6" } }, "nbformat": 4,