{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Day 6 - Voronoi diagram\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"Manhattan Voronoi diagram \n",
"Balu Ertl [CC BY-SA 1.0], from Wikimedia Commons\n",
"\n",
"\n",
"\n",
"\n",
"- [Day 6](https://adventofcode.com/2018/day/6)\n",
"\n",
"Another computational geometry problem! This time we are asked to find the largest area in a [Voronoi diagram](https://en.wikipedia.org/wiki/Voronoi_diagram).\n",
"\n",
"The most efficient algorithm to produce the boundaries between the points ($O(n \\log_2 n)$) is [Fortune's algorithm](https://en.wikipedia.org/wiki/Fortune%27s_algorithm), which (like [day 3](./Day%2003.ipynb)) is a [sweep line algorithm](https://en.wikipedia.org/wiki/Sweep_line_algorithm) to reduce the problem from 2 to 1 dimension. _But_, we don't need boundaries, we need _area_. A simpler method is to just use a $O(kn)$ double loop to find which of $n$ elements is closest for each of the $k$ `(x, y)` points in the map.\n",
"\n",
"There are three importand aspects to remember here:\n",
"\n",
"1. we need to use [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry), not Euclidian distance, when doing our calculations.\n",
"\n",
"2. If 2 or more coordinates are equidistant from a given `(x, y)` point, that point doesn't count as area for any of the coordinates. This means we can't just use `min()` here, and `sort()` would be needlessly precise. Instead, we only need to know the _top 2 smallest distances_; if these two are equidistance we know we can't give the area to anyone. To get the two N of anything, you'd want to use a [heap queue](https://docs.python.org/3/library/heapq.html#heapq.nsmallest), which gives us the result in $O(n)$ time rather than $O(n \\log_2 n)$. Or, for numpy arrays, use the [`numpy.partition()`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.partition.html) function; we just want to group the top two separate from the remainder, it doesn't matter if they are ordered any further, after all.\n",
"\n",
"3. Per coordinate we need to track if their area stretches to infinity, so we can disqualify them from consideration when we ask for the maximum area. Any coordinate that can claim a `(x, y)` point on the boundaries (defined as the min and max x and y coordinates) can be expected to stretch to infinity.\n",
"\n",
"All computations can be done with numpy arrays, and the distance calculations can be done for all points for the whole matrix in one step with the Scipy [`scipy.spacial.distance.cdist()`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html) function, which directly supports calculating Manhattan distances.\n",
"\n",
"As inputs we need\n",
"\n",
"- an array for all the `(x, y)` positions for the coordinates\n",
"\n",
"
\n",
" \n",
"
#
x
y
\n",
" \n",
" \n",
"
0
1
1
\n",
"
1
1
6
\n",
"
⋮
⋮
⋮
\n",
"
5
8
9
\n",
" \n",
"
\n",
"\n",
"- an array of all possible `(x, y)` coordinates for the grid\n",
" bounded the min and max x, y coordinates of the input coordinates\n",
"\n",
"
\n",
" \n",
"
#
x
y
\n",
" \n",
" \n",
"
0
1
1
\n",
"
1
2
1
\n",
"
2
3
1
\n",
"
⋮
⋮
⋮
\n",
"
55
7
8
\n",
" \n",
"
\n",
"\n",
"Given these, `cdist()` will give us a big matrix with all distances:\n",
"\n",
"
\n",
" \n",
"
#
distances
\n",
" \n",
" \n",
"
0
\n",
"
\n",
" \n",
"
0
1
2
3
4
5
6
\n",
" \n",
"
0
0.0
1.0
2.0
3.0
4.0
5.0
6.0
\n",
"
1
1.0
2.0
3.0
4.0
5.0
6.0
7.0
\n",
"
⋮
⋮
⋮
⋮
⋮
⋮
⋮
⋮
\n",
"
7
7.0
8.0
9.0
10.0
11.0
12.0
13.0
\n",
" \n",
"
\n",
"
\n",
"
1
\n",
"
\n",
" \n",
"
0
1
2
3
4
5
6
\n",
" \n",
" \n",
"
0
5.0
6.0
7.0
8.0
9.0
10.0
11.0
\n",
"
1
4.0
5.0
6.0
7.0
8.0
9.0
10.0
\n",
"
⋮
⋮
⋮
⋮
⋮
⋮
⋮
⋮
\n",
"
7
2.0
3.0
4.0
5.0
6.0
7.0
8.0
\n",
" \n",
"
\n",
"
\n",
"
⋮
⋮
\n",
"
5
\n",
"
\n",
" \n",
"
0
1
2
3
4
5
6
\n",
" \n",
" \n",
"
0
15.0
14.0
13.0
12.0
11.0
10.0
9.0
\n",
"
1
14.0
13.0
12.0
11.0
10.0
9.0
8.0
\n",
"
⋮
⋮
⋮
⋮
⋮
⋮
⋮
⋮
\n",
"
7
8.0
7.0
6.0
5.0
4.0
3.0
2.0
\n",
" \n",
"
\n",
"
\n",
" \n",
"
\n",
"\n",
"All that then remains to be done is find the _ids_ of the input coordinates (integer index) that have the lowest distance at each point, remove the points at which the lowest distance and second lowest distance are equal (contested distances), remove the ids that claim area at the edges (those have infinite area), then count the ids and return the highest of those counts.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from scipy.spatial import distance\n",
"\n",
"\n",
"def _manhattan_distances_matrix(coords):\n",
" \"\"\"Produce a len(coords) matrix of manhattan distances at all possible x, y\"\"\"\n",
" x = np.arange(coords[..., 0].min(), coords[..., 0].max() + 1)\n",
" y = np.arange(coords[..., 1].min(), coords[..., 1].max() + 1)\n",
" # arrays with len(x) x len(y) x and y coordinates\n",
" xx, yy = np.meshgrid(x, y)\n",
" # array of all possible [x, y]\n",
" all_xy = np.stack((xx, yy), axis=-1).reshape(-1, 2)\n",
"\n",
" # calculate distances for all points at all coordinates; essentially a\n",
" # len(coordinates) set of matrices of distances\n",
" return distance.cdist(coords, all_xy, metric=\"cityblock\").reshape(-1, *xx.shape)\n",
"\n",
"\n",
"def _claimed_area(coords):\n",
" \"\"\"matrix of claimed areas by id; -1 is used to mark equidistanc areas.\"\"\"\n",
" distances = _manhattan_distances_matrix(coords)\n",
"\n",
" # What coordinate ids win for a given x, y position?\n",
" coord_ids = distances.argmin(axis=0)\n",
"\n",
" # whereever the top and second best distance are the same, clear the\n",
" # claim for a candidate id\n",
" candidate, next_ = np.partition(distances, 2, axis=0)[:2]\n",
" coord_ids[candidate == next_] = -1\n",
"\n",
" return coord_ids\n",
"\n",
"\n",
"def find_max_area(coords):\n",
" \"\"\"How large is the largest non-infinite area covered?\"\"\"\n",
" coord_ids = _claimed_area(coords)\n",
"\n",
" # Any candidate id that's at the edge has infinite area, clear those\n",
" # from consideration\n",
" is_infinite = np.union1d(\n",
" # top and bottom\n",
" np.unique(coord_ids[[0, -1], :]),\n",
" # left and right\n",
" np.unique(coord_ids[:, [0, -1]]),\n",
" )\n",
" coord_ids[np.isin(coord_ids, is_infinite)] = -1\n",
"\n",
" # now we have a matrix of all positions on the infinite grid (bounded\n",
" # by the min and max coordinates) with non-infinite areas marked by\n",
" # the id of the coordinates that claim that position. -1 mark spots\n",
" # not claimable or part of an infinite area. All we need to do now is\n",
" # count the ids != -1, and return the maximum\n",
" _, counts = np.unique(coord_ids[coord_ids != -1], return_counts=True)\n",
" return counts.max()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"testcoords = np.genfromtxt(\n",
" \"\"\"\\\n",
"1, 1\n",
"1, 6\n",
"8, 3\n",
"3, 4\n",
"5, 5\n",
"8, 9\"\"\".splitlines(),\n",
" delimiter=\",\",\n",
" dtype=np.int32,\n",
")\n",
"assert find_max_area(testcoords) == 17"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"from PIL import Image\n",
"\n",
"\n",
"def visualise(coords, cmap=\"rainbow\", unclaimed=\"black\", centers=\"white\", ratio=1):\n",
" coord_ids = _claimed_area(coords)\n",
" vmax = coord_ids.max()\n",
"\n",
" # mark the coordinate centers with a separate colour; coordinates\n",
" # must first be normalised as we don't necessarily start at 0, 0\n",
" # anymore.\n",
" normalised_coords = coords - coords.min(axis=0)\n",
" coord_ids[tuple(normalised_coords.T)[::-1]] = vmax + 1\n",
"\n",
" # Generate a PIL image, using a matplotlib palette\n",
" # resample a matplotlib colour map to cover our coords count (vmax + 1)\n",
" p = plt.get_cmap(cmap).resampled(vmax + 1)\n",
" # -1 is given one colour\n",
" p.set_under(unclaimed)\n",
" # vmax + 1 another\n",
" p.set_over(centers)\n",
" # map points through the resampled palette\n",
" img = Image.fromarray(p(coord_ids, bytes=True))\n",
" if ratio != 1:\n",
" img = img.resize(\n",
" (int(img.size[0] * ratio), int(img.size[1] * ratio)),\n",
" Image.Resampling.NEAREST,\n",
" )\n",
" return img\n",
"\n",
"\n",
"visualise(testcoords, ratio=35)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import aocd\n",
"\n",
"data = aocd.get_data(day=6, year=2018)\n",
"coords = np.genfromtxt(data.splitlines(), delimiter=\",\", dtype=np.uint)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Part 1: 4060\n"
]
}
],
"source": [
"print(\"Part 1:\", find_max_area(coords))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# All the coordinates mapped out:\n",
"visualise(coords)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Part 2\n",
"\n",
"This part is actually easier, we can sum all the distances that `cdist()` gives us for all possible positions, and count how many of these fall below the threshold. Numpy was made for this kind of work.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def area_within_threshold(coords, threshold):\n",
" distances = _manhattan_distances_matrix(coords)\n",
" return (distances.sum(axis=0) < threshold).sum()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"testthreshold = 32\n",
"assert area_within_threshold(testcoords, testthreshold) == 16"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAVwAAAGFCAYAAACxJ0vLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAFoklEQVR4nO3bMXLCQBBFQa9LV4RDikOOj2AF1pNB3fEGvyh4NQlrZuYLgNN9Xz0A4C4EFyAiuAARwQWICC5ARHABIoILEBFcgMh29OFa68wdAG/tyH/IXLgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAke3qAXezP+bqCYSer3X1BP4RFy5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWIbFcP+Ev7Y66e8KvnfvUCSvvzDb6Tr3X1hNtw4QJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASKCCxARXICI4AJE1szMoYdrnb3lFvbHoY+bD/F8+d3cxZGUunABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABIoILEBFcgIjgAkQEFyAiuAARwQWICC5ARHABImtm5tDDtc7eAvC2jqTUhQsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAiOACRAQXICK4ABHBBYgILkBEcAEiggsQEVyAyHb04cycuQPg47lwASKCCxARXICI4AJEBBcgIrgAEcEFiAguQERwASI/xK8nAH9FCHcAAAAASUVORK5CYII=",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def plot_area(coords, threshold):\n",
" cmap = plt.get_cmap(\"cool\")\n",
" cmap.set_over(\"black\")\n",
" distance = _manhattan_distances_matrix(coords).sum(axis=0)\n",
" plt.axis(\"off\")\n",
" plt.imshow(distance, vmax=threshold - 1, cmap=cmap)\n",
"\n",
"\n",
"plot_area(testcoords, testthreshold)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Part 2: 36136\n"
]
}
],
"source": [
"threshold = 10000\n",
"print(\"Part 2:\", area_within_threshold(coords, threshold))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_area(coords, threshold)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}