 My attempts to work through the 2021 Advent of Code problems.

```commit 5478829a2bdfece833624da2f20828451d70702e
parent cc54381e861ab4c06c07210cdfc8b68c88f6f862
Date:   Wed, 15 Dec 2021 18:40:50 -0500

New grid_to_distance_matrix is almost 17x faster

Diffstat:
Mday15_part1.py | 66+++++++++++++++++++++++++-----------------------------------------
```
```1 file changed, 25 insertions(+), 41 deletions(-)
diff --git a/day15_part1.py b/day15_part1.py
@@ -32,51 +32,35 @@ def grid_to_distance_matrix(input_array: np.ndarray) -> csr_matrix:
# indicies into the original 2d array in the distance matrix: e.g., the
# last element in a 3x3 array has index 8 (thanks to zero-indexing), and is
# connected to index 7 (to its left) and index 5 (above it), so the sparse
-    # distance matrix will have connections in row 8 at columns 5 and 7.  I
-    # believe that this function could be much more efficient by being smart
-    # with divmod, but it's only run once per solution, so the easier-to-debug
-    # implementation wins the day. Also note that this is a _directed_
-    # distance/connectivity/association matrix, because the cost of going from
-    # #8 to #7 isn't necessarily teh same as going from #7 to #8.
-    dist_row_ids = []
-    dist_col_ids = []
-    dist_data = []
-    for grid_row_id in range(input_array.shape):
-        for grid_col_id in range(input_array.shape):
-            dist_row_id = grid_row_id * input_array.shape + grid_col_id
-            if grid_row_id >= 1:
-                # Top neighbor
-                dist_row_ids.append(dist_row_id)
-                dist_col_ids.append(dist_row_id - \
-                                    input_array.shape)
-                dist_data.append(input_array[grid_row_id - 1,
-                                             grid_col_id])
+    # distance matrix will have connections in row 8 at columns 5 and 7. Note
+    # that this is a _directed_ distance/connectivity/association matrix,
+    # because the cost of going from #8 to #7 isn't necessarily the same as
+    # going from #7 to #8.

-            if grid_row_id < (input_array.shape - 1):
-                # Bottom neighbor
-                dist_row_ids.append(dist_row_id)
-                dist_col_ids.append(dist_row_id + \
-                                    input_array.shape)
-                dist_data.append(input_array[grid_row_id + 1,
-                                             grid_col_id])
+    # In the (sparse) distance matrix, data will be stored as:
+    # Row: node id (row-major indexing), Col: neighbor id
+    # We'll start off by pretending that every node has four neighbors
+    dist_row_ids = np.repeat(np.arange(input_array.size, dtype=int), 4)
+    dist_col_ids = np.empty_like(dist_row_ids)
+    dist_col_ids[0::4] = dist_row_ids[0::4] - 1                     # Left
+    dist_col_ids[1::4] = dist_row_ids[1::4] + 1                     # Right
+    dist_col_ids[2::4] = dist_row_ids[2::4] - input_array.shape  # Top
+    dist_col_ids[3::4] = dist_row_ids[3::4] + input_array.shape  # Bottom

-            if grid_col_id >= 1:
-                # Left neighbor
-                dist_row_ids.append(dist_row_id)
-                dist_col_ids.append(dist_row_id - 1)
-                dist_data.append(input_array[grid_row_id,
-                                             grid_col_id - 1])
-
-            if grid_col_id < (input_array.shape - 1):
-                # Right neighbor
-                dist_row_ids.append(dist_row_id)
-                dist_col_ids.append(dist_row_id + 1)
-                dist_data.append(input_array[grid_row_id,
-                                             grid_col_id + 1])
+    # Now we remove the invalid neighbors (at the edges)
+    grid_col_ids = dist_row_ids % input_array.shape
+    grid_row_ids = dist_row_ids // input_array.shape
+    keep_neighbor = np.empty_like(grid_col_ids, dtype=bool)
+    keep_neighbor[0::4] = grid_col_ids[0::4] >= 1
+    keep_neighbor[1::4] = grid_col_ids[1::4] < (input_array.shape - 1)
+    keep_neighbor[2::4] = grid_row_ids[2::4] >= 1
+    keep_neighbor[3::4] = grid_row_ids[3::4] < (input_array.shape - 1)
+    dist_row_ids = dist_row_ids[keep_neighbor]
+    dist_col_ids = dist_col_ids[keep_neighbor]

# There are a bunch of ways to instantiate a csr_matrix, this is the most
-    # appropriate for these data
-    return csr_matrix((dist_data,
+    # appropriate for this data format
+    return csr_matrix((np.reshape(input_array, input_array.size)[dist_col_ids],
(dist_row_ids, dist_col_ids)))

def find_shortest_path(distance_matrix: csr_matrix):
```