\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 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",
"# Preliminaries: Imports and Utilities\n",
"\n",
"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": {},
"outputs": [],
"source": [
"%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, 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(1 for item in iterable if predicate(item)) \n",
"\n",
"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": [
"# 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": {},
"outputs": [],
"source": [
"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 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": [
"Here are all the strings of length 3:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'BBB', 'BBW', 'BWB', 'BWW', 'WBB', 'WBW', 'WWB', 'WWW'}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"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": {},
"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}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{n: enumerate_barcodes(n) for n in range(13)}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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",
"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": 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 11.3 ms, sys: 643 µs, total: 12 ms\n",
"Wall time: 12.6 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: 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": [
"