Add files via upload

This commit is contained in:
Peter Norvig 2025-12-10 22:51:27 -08:00 committed by GitHub
parent 671e8e4849
commit 38cc88deda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -81,7 +81,7 @@
} }
], ],
"source": [ "source": [
"def parse_rotation(line: str): return int(line.replace('L', '-').replace('R', '+'))\n", "def parse_rotation(line: str) -> str: return int(line.replace('L', '-').replace('R', '+'))\n",
"\n", "\n",
"rotations = parse(day=1, parser=parse_rotation) " "rotations = parse(day=1, parser=parse_rotation) "
] ]
@ -150,7 +150,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.1: .0006 seconds, answer 1182 correct" "Puzzle 1.1: .0005 seconds, answer 1182 correct"
] ]
}, },
"execution_count": 5, "execution_count": 5,
@ -184,7 +184,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.2: .1378 seconds, answer 6907 correct" "Puzzle 1.2: .1396 seconds, answer 6907 correct"
] ]
}, },
"execution_count": 6, "execution_count": 6,
@ -234,7 +234,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.2: .0009 seconds, answer 6907 correct" "Puzzle 1.2: .0010 seconds, answer 6907 correct"
] ]
}, },
"execution_count": 8, "execution_count": 8,
@ -379,7 +379,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 2.1: .0031 seconds, answer 23560874270 correct" "Puzzle 2.1: .0037 seconds, answer 23560874270 correct"
] ]
}, },
"execution_count": 12, "execution_count": 12,
@ -463,7 +463,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 2.1: .0029 seconds, answer 23560874270 correct" "Puzzle 2.1: .0027 seconds, answer 23560874270 correct"
] ]
}, },
"execution_count": 15, "execution_count": 15,
@ -485,7 +485,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 2.2: .0038 seconds, answer 44143124633 correct" "Puzzle 2.2: .0040 seconds, answer 44143124633 correct"
] ]
}, },
"execution_count": 16, "execution_count": 16,
@ -671,7 +671,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 3.1: .0006 seconds, answer 17085 correct" "Puzzle 3.1: .0007 seconds, answer 17085 correct"
] ]
}, },
"execution_count": 23, "execution_count": 23,
@ -693,7 +693,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 3.2: .0024 seconds, answer 169408143086082 correct" "Puzzle 3.2: .0019 seconds, answer 169408143086082 correct"
] ]
}, },
"execution_count": 24, "execution_count": 24,
@ -792,7 +792,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.1: .0525 seconds, answer 1569 correct" "Puzzle 4.1: .0534 seconds, answer 1569 correct"
] ]
}, },
"execution_count": 27, "execution_count": 27,
@ -843,7 +843,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.2: 1.2227 seconds, answer 9280 correct" "Puzzle 4.2: 1.2283 seconds, answer 9280 correct"
] ]
}, },
"execution_count": 29, "execution_count": 29,
@ -892,7 +892,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.2: .1387 seconds, answer 9280 correct" "Puzzle 4.2: .1393 seconds, answer 9280 correct"
] ]
}, },
"execution_count": 31, "execution_count": 31,
@ -987,7 +987,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 5.1: .0073 seconds, answer 635 correct" "Puzzle 5.1: .0075 seconds, answer 635 correct"
] ]
}, },
"execution_count": 34, "execution_count": 34,
@ -1235,7 +1235,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 6.2: .0038 seconds, answer 11159825706149 correct" "Puzzle 6.2: .0043 seconds, answer 11159825706149 correct"
] ]
}, },
"execution_count": 42, "execution_count": 42,
@ -1447,7 +1447,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 7.1: .0008 seconds, answer 1681 correct" "Puzzle 7.1: .0007 seconds, answer 1681 correct"
] ]
}, },
"execution_count": 50, "execution_count": 50,
@ -1481,7 +1481,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 7.2: .0015 seconds, answer 422102272495018 correct" "Puzzle 7.2: .0013 seconds, answer 422102272495018 correct"
] ]
}, },
"execution_count": 51, "execution_count": 51,
@ -1568,7 +1568,7 @@
"\n", "\n",
"The goal is to start connecting junction boxes, starting with the two boxes that are closest to each other in 3D space, then the next two closest, and so on. (I assume that a box can connect to an unlimited number of other boxes.) After connecting the 1000 pairs that are closest together, what do you get if you multiply together the sizes of the three largest circuits?\n", "The goal is to start connecting junction boxes, starting with the two boxes that are closest to each other in 3D space, then the next two closest, and so on. (I assume that a box can connect to an unlimited number of other boxes.) After connecting the 1000 pairs that are closest together, what do you get if you multiply together the sizes of the three largest circuits?\n",
"\n", "\n",
"I recognize this as a [**greedy algorithm**](https://en.wikipedia.org/wiki/Greedy_algorithm), consuming shortest links first, and I've [done that before](TSP.ipynb). I also recognize this as a [**Union-Find**](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) problem, and I know there are efficient data structures for that problem. However, for this problem we don't make heavy use of the union-find functionality, so keeping it simple seems to be the best result. (After finishing my code I feel vindicated: I see in my [other notebook](Advent2025-AI.ipynb) that Claude Opus 4.5 implemented a Union-Find data structure, and ended up with code that ran slower than my simpler approach.)\n", "I recognize this as a [**greedy algorithm**](https://en.wikipedia.org/wiki/Greedy_algorithm), consuming shortest links first, and I've [done that before](TSP.ipynb). I also recognize this as a [**Union-Find**](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) problem, and I know there are efficient data structures for that problem. However, for this problem we don't make heavy use of the union-find functionality, so keeping it simple seems to be the best approach. (After finishing my code I feel vindicated: I see in my [other notebook](Advent2025-AI.ipynb) that Claude Opus 4.5 implemented a Union-Find data structure, and ended up with code that ran slower than my simpler approach.)\n",
"\n", "\n",
"The function `greedy_connect` will keep a dict that maps each box to the circuit it is part of (initially just itself), and update that dict when two circuits are connected together. Then I'll go through the 1000 `closest_pairs` of boxes, updating the dict for each one, and return the dict at the end. Then the function `largest` will find the largest 3 circuits, and `prod` will multiply the sizes together." "The function `greedy_connect` will keep a dict that maps each box to the circuit it is part of (initially just itself), and update that dict when two circuits are connected together. Then I'll go through the 1000 `closest_pairs` of boxes, updating the dict for each one, and return the dict at the end. Then the function `largest` will find the largest 3 circuits, and `prod` will multiply the sizes together."
] ]
@ -1615,7 +1615,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 8.1: .5858 seconds, answer 24360 correct" "Puzzle 8.1: .5880 seconds, answer 24360 correct"
] ]
}, },
"execution_count": 54, "execution_count": 54,
@ -1667,7 +1667,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 8.2: .6383 seconds, answer 2185817796 correct" "Puzzle 8.2: .6032 seconds, answer 2185817796 correct"
] ]
}, },
"execution_count": 56, "execution_count": 56,
@ -1783,7 +1783,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 9.1: .0267 seconds, answer 4772103936 correct" "Puzzle 9.1: .0266 seconds, answer 4772103936 correct"
] ]
}, },
"execution_count": 59, "execution_count": 59,
@ -1868,7 +1868,7 @@
" i = max(range(-1, len(red_tiles) - 1), key=lambda i: distance(red_tiles[i], red_tiles[i + 1]))\n", " i = max(range(-1, len(red_tiles) - 1), key=lambda i: distance(red_tiles[i], red_tiles[i + 1]))\n",
" return red_tiles[i+1:i+3]\n", " return red_tiles[i+1:i+3]\n",
" \n", " \n",
"def breadcrumbs(points, d=10000):\n", "def breadcrumbs(points, d=10000) -> List[Point]:\n",
" \"\"\"Leave extra points along the trail on long lines, every `d` spaces.\"\"\"\n", " \"\"\"Leave extra points along the trail on long lines, every `d` spaces.\"\"\"\n",
" trail = [points[-1]]\n", " trail = [points[-1]]\n",
" for p in points:\n", " for p in points:\n",
@ -2065,8 +2065,8 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"CPU times: user 3.62 s, sys: 79.9 ms, total: 3.7 s\n", "CPU times: user 3.47 s, sys: 82.4 ms, total: 3.55 s\n",
"Wall time: 3.06 s\n" "Wall time: 2.94 s\n"
] ]
} }
], ],
@ -2081,7 +2081,7 @@
"source": [ "source": [
"Two remarks to be made here. One, this was the first puzzle of the year that was **difficult**. Two, my solution is **unsatisfying** in that it works for *my* input, and I strongly suspect that it would work for *your* input, because Eric Wastl probably creating them all to be similar. But it does not work on every possible input allowed by the rules. \n", "Two remarks to be made here. One, this was the first puzzle of the year that was **difficult**. Two, my solution is **unsatisfying** in that it works for *my* input, and I strongly suspect that it would work for *your* input, because Eric Wastl probably creating them all to be similar. But it does not work on every possible input allowed by the rules. \n",
"\n", "\n",
"To cover every possible input I couldn't split the red tiles in half; I would need to consider all pairs of tile locations as possible corners. And the `any_intrusions` function would have to be more complex. See [ChatGPT's solution to 9.2](Advent-2025-AI.ipynb) for example; in general `any_intrusions` would have to cover an intrusion that spans the whole rectangle (and thus does not have a tile point inside the rectangle), as well as recognizing that if two points that are adjacent are inside the rectangle, that is not an intrusion of a non-red tile; that's just a two-wide strip of red." "To cover every possible input I couldn't rely on `find_possible_corners`. I would need to be careful in choosing the value of `d` for `breadcrumbs`; perhaps iterating on different values. The `any_intrusions` function would have to be more complex. See [ChatGPT's solution to 9.2](Advent-2025-AI.ipynb) for example; `any_intrusions` would have to recognize that if two points that are adjacent are inside the rectangle, that is not an intrusion of a non-red tile; that's just a two-wide strip of red."
] ]
}, },
{ {
@ -2091,11 +2091,11 @@
"source": [ "source": [
"# [Day 10](https://adventofcode.com/2025/day/10): Factory\n", "# [Day 10](https://adventofcode.com/2025/day/10): Factory\n",
"\n", "\n",
"Today we find the machines in the factory are offline. Each machine has some lights, some buttons that can be pressed, and some joltage requirements, all of which is described in the manual. For example, the machine:\n", "Today we find the machines in the factory are offline. Each machine has some lights, some buttons that can be pressed, and a joltage requirement for each light. For example, the machine described by:\n",
"\n", "\n",
" [.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}\n", " [.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}\n",
"\n", "\n",
"has four lights, and the goal configuration is to have the second and third turned on (`.##.`). There are six buttons (each within parentheses): the first toggles light number 3 (with zero-based indexing), the second toggles lights 1 and 3, and so on. Finally, the joltage requirements for the four lights are `3,5,4,7`. We can parse the input lines into machine descriptions like this:" "has four lights, and the goal configuration `.##.` means that the second and third light should be on and the others off. There are six buttons (each delimited by parentheses): the first button toggles light number 3, the second toggles lights 1 and 3, and so on. (The machine uses 0-based indexing.) Finally, the joltage requirements for the four lights are `3,5,4,7`. We can parse the input lines into machine descriptions like this:"
] ]
}, },
{ {
@ -2166,7 +2166,7 @@
" First try all ways of pressing 1 button, then all ways of pressing 2, ...\n", " First try all ways of pressing 1 button, then all ways of pressing 2, ...\n",
" Return as soon as one way matches the goal configuration of lights.\"\"\"\n", " Return as soon as one way matches the goal configuration of lights.\"\"\"\n",
" lights, buttons, joltage = machine\n", " lights, buttons, joltage = machine\n",
" goal = [\".#\".index(ch) for ch in lights] # Use 0|1 instead of \".|#\"\n", " goal = [\".#\".index(ch) for ch in lights] # i.e., lights = \".##.\" ⇒ goal = (0, 1, 1, 0)\n",
" for pressed in powerset(buttons):\n", " for pressed in powerset(buttons):\n",
" # Check that total presses for each light mod 2 is equal to goal for that light\n", " # Check that total presses for each light mod 2 is equal to goal for that light\n",
" presses = Counter(flatten(pressed))\n", " presses = Counter(flatten(pressed))\n",
@ -2184,7 +2184,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 10.1: .0560 seconds, answer 441 correct" "Puzzle 10.1: .0531 seconds, answer 441 correct"
] ]
}, },
"execution_count": 71, "execution_count": 71,
@ -2204,45 +2204,16 @@
"source": [ "source": [
"### Part 2: What is the fewest button presses to configure the joltage levels on all the machines?\n", "### Part 2: What is the fewest button presses to configure the joltage levels on all the machines?\n",
"\n", "\n",
"In Part 2 we move a lever, and now the buttons control the joltage levels of the lights, not the lights themselves. The joltage levels all start at zero pressing the button `(2, 3)` increments the joltage level of lights numbered 2 and 3 by one unit. Our task is to get the joltage levels all exactly to the target levels in the minimum number of presses.\n", "In Part 2 we move a lever, and now the buttons control the joltage levels of the lights, not the lights themselves. The joltage levels all start at zero. Pressing the button `(2, 3)` increments the joltage level of lights numbered 2 and 3 by one unit each. Our task is to get the joltage levels all exactly to the target levels in the minimum number of presses.\n",
"\n", "\n",
"My first thought when reading the puzzle description was \"*This is an [integer linear programming](https://en.wikipedia.org/wiki/Integer_programming) problem.*\" My thought was confirmed by the instructions that said \"*You have to push each button an integer number of times; there's no such thing as \"0.5 presses\" (nor can you push a button a negative number of times).*\" because having fractional or negative results is exactly what you get from linear programming; you have to take extra steps to constrain the results to be non-negative and to be integers.\n", "My first thought when reading the puzzle description was \"*This is an [integer linear programming](https://en.wikipedia.org/wiki/Integer_programming) problem.*\" My thought was confirmed by the instructions that said \"*You have to push each button an integer number of times; there's no such thing as 0.5 presses (nor can you push a button a negative number of times).*\" because having fractional or negative results is exactly what you might get from linear programming; you have to take extra steps to constrain the results to be non-negative and to be integers.\n",
"\n", "\n",
"Still, I was reluctant to use an integer linear programming package; that would nmean that someone else is writing most of the code for the solution. I started programming an A* search solution, but it was way too slow. Why is it slow? Let's investigate. First, the number of machines is no problem:" "Still, I was reluctant to use an integer linear programming package; that would mean that someone else is writing most of the code for the solution. I started programming an A* search solution, but it was way too slow. Why is it slow? Let's investigate. First, the number of buttons per machine is not too bad:"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 72, "execution_count": 72,
"id": "2bb1b0ff-3b3d-4d9a-b978-fa988bcc9038",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"165"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(machines)"
]
},
{
"cell_type": "markdown",
"id": "f58993d4-fcef-4d6f-b11e-558f586cf9a5",
"metadata": {},
"source": [
"The number of buttons per machine is not too bad:"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "1d2683fa-5126-4d2a-9dad-6a0e155f3449", "id": "1d2683fa-5126-4d2a-9dad-6a0e155f3449",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2252,7 +2223,7 @@
"7.181818181818182" "7.181818181818182"
] ]
}, },
"execution_count": 73, "execution_count": 72,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -2271,7 +2242,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 74, "execution_count": 73,
"id": "a714c2c2-d433-41d0-8d1e-01832b35a1a9", "id": "a714c2c2-d433-41d0-8d1e-01832b35a1a9",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2281,7 +2252,7 @@
"114.81498043610085" "114.81498043610085"
] ]
}, },
"execution_count": 74, "execution_count": 73,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -2298,24 +2269,24 @@
"That means a completely naive search would have to consider about 7<sup>115</sup> possible button press sequences. Of course we can make some optimizations:\n", "That means a completely naive search would have to consider about 7<sup>115</sup> possible button press sequences. Of course we can make some optimizations:\n",
"- Many joltage states will be repeated; we can cache them.\n", "- Many joltage states will be repeated; we can cache them.\n",
"- Button presses are commutative; we can impose a canonical ordering.\n", "- Button presses are commutative; we can impose a canonical ordering.\n",
"- We can keep track of the best solution found so far and eliminate states that can't reach the goal in that number of steps.\n", "- We can keep track of the best solution found so far and eliminate states that can't reach the goal in that number of presses.\n",
"- Some actions will be forced: if there is only one button that increments a given light, we *must* press it until the light hits its goal.\n", "- Some actions will be forced: if there is only one button that increments a given light, we *must* press it until the light hits its goal.\n",
"\n", "\n",
"Unfortunately, I couldn't come up with enough ideas to make the search fast, so I gave in and accepted the dark side of integer programming.\n", "Unfortunately, I couldn't come up with enough ideas to make the search fast, so I gave in and accepted the dark side of integer programming.\n",
"\n", "\n",
"I started researching integer programming packages that run in Python. [Z3](https://github.com/Z3Prover/z3) seems to be the most popular, but it is a separate step to install it. I (and many other people) already have **scipy** installed, and the [**scipy.optimize**](https://docs.scipy.org/doc/scipy/tutorial/optimize.html) package contains the function [**milp**](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.milp.html#scipy.optimize.milp), for \"mixed integer linear programming.\" The \"linear\" part is appropriate: we have variables (i.e., the buttons) which have coefficients (the number of presses) that must add up to the right total (the joltage requirements). The \"mixed\" part means that we can declare that some of the variables must be integers, while others can be continuous. (For our problem they will all be integers.)\n", "I started researching integer programming packages that run in Python. [Z3](https://github.com/Z3Prover/z3) seems to be the most popular, but it is a separate step to install it. I know that I (and many other people) already have **scipy** installed, and the [**scipy.optimize**](https://docs.scipy.org/doc/scipy/tutorial/optimize.html) package contains the function [**milp**](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.milp.html#scipy.optimize.milp), for \"mixed integer linear programming.\" The \"linear\" part is appropriate: we have variables (i.e., the buttons) which have coefficients (the number of presses) that must add up to the right total (the joltage requirements). The \"mixed\" part means that we can declare that some of the variables must be integers, while others can be continuous. (For our problem they will all be integers.)\n",
"\n", "\n",
"The arguments to **milp** are:\n", "The arguments to **milp** are:\n",
"- **c**: a cost function to be minimized. Represented by coefficients, one per variable. For our problem, each button press counts one, so this will be an array of ones.\n", "- **c**: a cost function to be minimized. Represented by coefficients, one per variable. For our problem, each button press counts one, so this will be an array of ones.\n",
"- **integrality**: indicates which variables must be integers. For our problem they all are, so this is also an array of ones (`1` means `True`).\n", "- **integrality**: indicates which variables must be integers. For our problem they all are, so this is also an array of ones (`1` means `True`).\n",
"- **constraints**: a linear constraint, which says that we want to find the array **x** of variable values such that *ub* ≤ **A** **x** ≤ *ub*, where *lb* and *ub* are the lower bounds and upper bounds. In our case **x** is the count of button presses for each button, and both upper and lower bounds are the joltage requirements (so **A** **x** must be exactly equal to the requirements), and **A** is a matrix such that **A**<sub>*i,j*</sub> says how much button *i* increments joltage *j* (this will be either 0 or 1).\n", "- **constraints**: a linear constraint, which says that we want to find values for the array **x** of variables such that *lb* ≤ **A** **x** ≤ *ub*, where *lb* and *ub* are the lower bounds and upper bounds. In our case **x** is the count of button presses for each button, and **A** is a matrix such that **A**<sub>*i,j*</sub> says how much button *i* increments joltage *j* (this will be either 0 or 1). Both upper and lower bounds are the joltage requirements (so the dot product **A** **x** must be exactly equal to the joltage requirements)\n",
"\n", "\n",
"If we give it the right inputs, **milp** will magically return an optimal result for **x** (an array of counts of number of button presses for each button). Here's how we get the data out of a `machine` and feed it to **milp**:" "If we give it the right inputs, **milp** will magically return an optimal result for **x** (an array of counts of number of button presses for each button). Here's how we get the data out of a `machine` and feed it to **milp**:"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 75, "execution_count": 74,
"id": "713a1503-ae14-445f-91ea-714fcd618ad0", "id": "713a1503-ae14-445f-91ea-714fcd618ad0",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -2323,7 +2294,7 @@
"from scipy.optimize import milp, LinearConstraint, Bounds\n", "from scipy.optimize import milp, LinearConstraint, Bounds\n",
"import numpy as np\n", "import numpy as np\n",
"\n", "\n",
"def minimal_joltage_presses(machine):\n", "def minimal_joltage_presses(machine) -> int:\n",
" \"\"\"The minimal number of button presses to set the joltage on this machine.\"\"\"\n", " \"\"\"The minimal number of button presses to set the joltage on this machine.\"\"\"\n",
" lights, buttons, joltage = machine\n", " lights, buttons, joltage = machine\n",
" A = T([[int(i in button) for i in range(len(lights))]\n", " A = T([[int(i in button) for i in range(len(lights))]\n",
@ -2345,17 +2316,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 76, "execution_count": 75,
"id": "46d0d274-bd4c-44af-83e9-35c791a8e96b", "id": "46d0d274-bd4c-44af-83e9-35c791a8e96b",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 10.2: .1173 seconds, answer 18559 correct" "Puzzle 10.2: .1154 seconds, answer 18559 correct"
] ]
}, },
"execution_count": 76, "execution_count": 75,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -2370,14 +2341,14 @@
"id": "7f597ab2-1569-478e-be09-b62c60c979d8", "id": "7f597ab2-1569-478e-be09-b62c60c979d8",
"metadata": {}, "metadata": {},
"source": [ "source": [
"This felt like cheating! I only wrote a few lines of code, and **milp** did the rest. My main contribution was just recognizing that this was an integer programming problem.\n", "**This felt like cheating!** I only wrote a few lines of code, and **milp** did the rest. My main contribution was just recognizing that this was an integer programming problem.\n",
"\n", "\n",
"Here are some tests on smaller machines:" "Here are some tests on smaller machines:"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 77, "execution_count": 76,
"id": "b72544c8-6069-4310-a6dc-b4acd77981b4", "id": "b72544c8-6069-4310-a6dc-b4acd77981b4",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -2404,7 +2375,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 78, "execution_count": 77,
"id": "11e17f6a-acba-44c4-b704-7e4ff7471e7e", "id": "11e17f6a-acba-44c4-b704-7e4ff7471e7e",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2455,7 +2426,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 79, "execution_count": 78,
"id": "7540a982-988a-4822-af0d-6581f6f848c6", "id": "7540a982-988a-4822-af0d-6581f6f848c6",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -2482,7 +2453,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 80, "execution_count": 79,
"id": "0c2d68a5-843b-49d6-aff6-23045968207f", "id": "0c2d68a5-843b-49d6-aff6-23045968207f",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2492,7 +2463,7 @@
"Puzzle 11.1: .0003 seconds, answer 574 correct" "Puzzle 11.1: .0003 seconds, answer 574 correct"
] ]
}, },
"execution_count": 80, "execution_count": 79,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -2514,7 +2485,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 81, "execution_count": 80,
"id": "0294e044-c7ef-418a-9c02-71615a453002", "id": "0294e044-c7ef-418a-9c02-71615a453002",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -2534,17 +2505,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 82, "execution_count": 81,
"id": "677a97b3-183b-474e-87ba-7db0d6b763d8", "id": "677a97b3-183b-474e-87ba-7db0d6b763d8",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 11.2: .0023 seconds, answer 306594217920240 correct" "Puzzle 11.2: .0022 seconds, answer 306594217920240 correct"
] ]
}, },
"execution_count": 82, "execution_count": 81,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -2566,7 +2537,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 83, "execution_count": 82,
"id": "4d512a50-c6ae-4803-a787-b8f6e0103e31", "id": "4d512a50-c6ae-4803-a787-b8f6e0103e31",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2574,30 +2545,30 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Puzzle 1.1: .0006 seconds, answer 1182 correct\n", "Puzzle 1.1: .0005 seconds, answer 1182 correct\n",
"Puzzle 1.2: .0009 seconds, answer 6907 correct\n", "Puzzle 1.2: .0010 seconds, answer 6907 correct\n",
"Puzzle 2.1: .0029 seconds, answer 23560874270 correct\n", "Puzzle 2.1: .0027 seconds, answer 23560874270 correct\n",
"Puzzle 2.2: .0038 seconds, answer 44143124633 correct\n", "Puzzle 2.2: .0040 seconds, answer 44143124633 correct\n",
"Puzzle 3.1: .0006 seconds, answer 17085 correct\n", "Puzzle 3.1: .0007 seconds, answer 17085 correct\n",
"Puzzle 3.2: .0024 seconds, answer 169408143086082 correct\n", "Puzzle 3.2: .0019 seconds, answer 169408143086082 correct\n",
"Puzzle 4.1: .0525 seconds, answer 1569 correct\n", "Puzzle 4.1: .0534 seconds, answer 1569 correct\n",
"Puzzle 4.2: .1387 seconds, answer 9280 correct\n", "Puzzle 4.2: .1393 seconds, answer 9280 correct\n",
"Puzzle 5.1: .0073 seconds, answer 635 correct\n", "Puzzle 5.1: .0075 seconds, answer 635 correct\n",
"Puzzle 5.2: .0001 seconds, answer 369761800782619 correct\n", "Puzzle 5.2: .0001 seconds, answer 369761800782619 correct\n",
"Puzzle 6.1: .0013 seconds, answer 5877594983578 correct\n", "Puzzle 6.1: .0013 seconds, answer 5877594983578 correct\n",
"Puzzle 6.2: .0038 seconds, answer 11159825706149 correct\n", "Puzzle 6.2: .0043 seconds, answer 11159825706149 correct\n",
"Puzzle 7.1: .0008 seconds, answer 1681 correct\n", "Puzzle 7.1: .0007 seconds, answer 1681 correct\n",
"Puzzle 7.2: .0015 seconds, answer 422102272495018 correct\n", "Puzzle 7.2: .0013 seconds, answer 422102272495018 correct\n",
"Puzzle 8.1: .5858 seconds, answer 24360 correct\n", "Puzzle 8.1: .5880 seconds, answer 24360 correct\n",
"Puzzle 8.2: .6383 seconds, answer 2185817796 correct\n", "Puzzle 8.2: .6032 seconds, answer 2185817796 correct\n",
"Puzzle 9.1: .0267 seconds, answer 4772103936 correct\n", "Puzzle 9.1: .0266 seconds, answer 4772103936 correct\n",
"Puzzle 9.2: .0309 seconds, answer 1529675217 correct\n", "Puzzle 9.2: .0309 seconds, answer 1529675217 correct\n",
"Puzzle 10.1: .0560 seconds, answer 441 correct\n", "Puzzle 10.1: .0531 seconds, answer 441 correct\n",
"Puzzle 10.2: .1173 seconds, answer 18559 correct\n", "Puzzle 10.2: .1154 seconds, answer 18559 correct\n",
"Puzzle 11.1: .0003 seconds, answer 574 correct\n", "Puzzle 11.1: .0003 seconds, answer 574 correct\n",
"Puzzle 11.2: .0023 seconds, answer 306594217920240 correct\n", "Puzzle 11.2: .0022 seconds, answer 306594217920240 correct\n",
"\n", "\n",
"Time in seconds: sum = 1.675, mean = .076, median = .003, max = .638\n" "Time in seconds: sum = 1.638, mean = .074, median = .003, max = .603\n"
] ]
} }
], ],