Skip to content

Commit 7a52a62

Browse files
committed
day15: part2 is 2545x faster
1 parent 097d851 commit 7a52a62

2 files changed

Lines changed: 66 additions & 39 deletions

File tree

day15.hs

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE TupleSections #-}
22

3+
import Criterion.Main
34
import Data.Function
45
import qualified Data.IntMap as IM
56
import Data.IntMap.Strict (IntMap)
@@ -12,21 +13,26 @@ type Grid = IntMap Int
1213

1314
type Pt = Int
1415

16+
factor :: Int
17+
factor = 10000
18+
1519
conv :: (Int, Int) -> Pt
16-
conv (x, y) = 10000 * x + y
20+
conv (x, y) = factor * x + y
1721

1822
from :: Pt -> (Int, Int)
19-
from n = (n `div` 10000, n `mod` 10000)
23+
from n = (n `div` factor, n `mod` factor)
2024

2125
toGrid :: [[Int]] -> Grid
2226
toGrid = IM.fromList . concat . zipWith (\x l -> zipWith (curry (\((x, a), y) -> (conv (x, y), a))) (map (x,) l) [1 ..]) [1 ..]
2327

28+
toGrid2 :: [[Int]] -> Grid
2429
toGrid2 = toGrid . embig
2530

2631
succW :: Int -> Int
2732
succW n = max ((n + 1) `mod` 10) 1
2833

29-
embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate (map succW) r) | r <- l]
34+
embig :: [[Int]] -> [[Int]]
35+
embig = concat . take 5 . iterate (map (map succW)) . map (concat . take 5 . iterate (map succW))
3036

3137
{-
3238
1 function Dijkstra(Graph, source):
@@ -35,7 +41,7 @@ embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate
3541
4
3642
5 for each vertex v in Graph:
3743
6 dist[v] ← INFINITY
38-
7 prev[v] ← UNDEFINED
44+
7 # prev[v] ← UNDEFINED
3945
8 add v to Q
4046
9 dist[source] ← 0
4147
10
@@ -48,19 +54,19 @@ embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate
4854
17 alt ← dist[u] + length(u, v)
4955
18 if alt < dist[v]:
5056
19 dist[v] ← alt
51-
20 prev[v] ← u
57+
20 # prev[v] ← u
5258
21
53-
22 return dist[], prev[]
59+
22 return dist[]
5460
-}
5561

5662
type PQueue a = IntMap [a]
5763

58-
pminView :: PQueue a -> (a, PQueue a)
64+
-- pminView :: PQueue a -> ((Key, a), PQueue a)
5965
pminView p =
6066
let Just (l, p') = IM.minViewWithKey p
6167
in case l of
6268
(_, []) -> pminView p
63-
(k, x : xs) -> (x, if null xs then IM.delete k p' else IM.insert k xs p')
69+
(k, x : xs) -> ((k, x), if null xs then IM.delete k p' else IM.insert k xs p')
6470

6571
pins :: Int -> a -> PQueue a -> PQueue a
6672
pins k x = IM.insertWith (++) k [x]
@@ -73,34 +79,36 @@ neighbors g p = IS.filter (`IM.member` g) (IS.fromList (conv <$> [(x -1, y), (x,
7379
where
7480
(x, y) = from p
7581

76-
dijkstra :: IntMap Int -> Int -> (IntMap Int, IntMap Int)
77-
dijkstra g s = step1 & step2 & step3
82+
dijkstra :: Grid -> Int -> IntMap Int
83+
dijkstra g s = step1 & step2
7884
where
79-
step1 = let c = IM.keysSet g; (a, b) = IS.foldl' go (mempty, mempty) c in (a, b, c)
80-
go (dv, pv) v = (dv', pv')
85+
step1 = let c = IM.keysSet g; a = IS.foldl' go mempty c in (a, c, pins 0 s pempty)
8186
where
82-
dv' = IM.insert v (maxBound :: Int) dv
83-
pv' = IM.insert v (conv (0, 0)) pv
84-
step2 (dv, pv, q) = (IM.insert s (conv (0, 0)) dv, pv, q)
85-
step3 (dv, pv, q)
86-
| IS.null q = (dv, pv)
87-
| otherwise = step3 (dv', pv', q')
87+
go dv v = IM.insert v (maxBound :: Int) dv
88+
step2 (dv, unseen, q)
89+
| IM.null q = dv
90+
| otherwise = step2 (dv', unseen', q'')
8891
where
89-
q' = IS.delete u q
90-
u = nextVert dv
91-
(dv', pv') = IS.foldl' f (dv, pv) (IS.intersection q (neighbors g u))
92+
-- u is the closest vertex to visit
93+
((d, u), q') = pminView q
94+
unseen' = IS.delete u unseen
95+
-- for all neighbors of u, visit it and thread the distance map and priority queue
96+
(dv', q'') = IS.foldl' visit (dv, q') (neighbors g u)
9297
where
93-
f (dv, pv) v = (dv'', pv'')
98+
-- to visit a point p', make sure it's in the graph
99+
visit (dv, q') p'
100+
| p' `IM.member` g = (dv'', q'')
101+
| otherwise = (dv, q')
94102
where
95-
alt = dv IM.! u + g IM.! v
96-
(dv'', pv'') = if alt < dv IM.! v then (IM.insert v alt dv, IM.insert v u pv) else (dv, pv)
97-
nextVert :: IntMap Int -> Int
98-
nextVert dv = v
99-
where
100-
v :: Int
101-
v = fst $ IS.foldl' (\(x, c) y -> if (dv IM.! y) < c then (y, dv IM.! y) else (x, c)) (undefined, maxBound :: Int) q
103+
-- compute the new distance to p' (store into alt) and
104+
-- compare against the previous distance
105+
alt = d + g IM.! p'
106+
-- if it's better then update distance for p' in dv to be alt
107+
(dv'', q'') = if alt < dv IM.! p' then (IM.insert p' alt dv, pins alt p' q') else (dv, q')
102108

103-
part1 (inp, n) = fst (dijkstra inp (conv (1, 1))) IM.! conv (n, n)
109+
part1 (inp, n) = dijkstra inp (conv (1, 1)) IM.! conv (n, n)
110+
111+
part2 = part1
104112

105113
main = do
106114
let dayNumber = 15 :: Int
@@ -110,14 +118,13 @@ main = do
110118
let x = map (map (read . pure)) . lines $ inp'
111119
let inp = toGrid x
112120
let inp2 = toGrid2 x
113-
let n = length (head $ lines $ inp')
121+
let n = length (head $ lines inp')
114122
print (part1 (inp, n))
115123
print (part1 (inp2, n * 5))
116-
117-
-- -- defaultMain
118-
-- -- [ bgroup
119-
-- -- dayString
120-
-- -- [ bench "part1" $ whnf part1 inp,
121-
-- -- bench "part2" $ whnf part2 inp
122-
-- -- ]
123-
-- -- ]
124+
defaultMain
125+
[ bgroup
126+
dayString
127+
[ bench "part1" $ whnf part1 (inp, n),
128+
bench "part2" $ whnf part2 (inp2, n * 5)
129+
]
130+
]

readme.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,26 @@ variance introduced by outliers: 55% (severely inflated)
348348
```
349349
</details>
350350

351+
### Day 15
352+
<details>
353+
354+
```
355+
benchmarking day15/part1
356+
time 28.84 ms (28.27 ms .. 29.51 ms)
357+
0.997 R² (0.992 R² .. 0.999 R²)
358+
mean 29.88 ms (29.11 ms .. 31.74 ms)
359+
std dev 2.642 ms (879.3 μs .. 4.691 ms)
360+
variance introduced by outliers: 34% (moderately inflated)
361+
362+
benchmarking day15/part2
363+
time 1.172 s (1.088 s .. 1.259 s)
364+
0.999 R² (0.997 R² .. 1.000 R²)
365+
mean 1.213 s (1.190 s .. 1.244 s)
366+
std dev 29.96 ms (12.16 ms .. 39.32 ms)
367+
variance introduced by outliers: 19% (moderately inflated)
368+
```
369+
</details>
370+
351371
### Day 16
352372
<details>
353373

0 commit comments

Comments
 (0)