From 37f5b0276e3c8858847f51290f15de169de82201 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sat, 24 Dec 2022 14:47:33 +0000 Subject: [PATCH 01/16] Done day 24 --- advent-of-code22.cabal | 6 +- advent24/Main.hs | 224 ++++++++++++++++++++++++++ data/advent24.txt | 27 ++++ data/advent24a.txt | 6 + problems/day24.html | 349 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 advent24/Main.hs create mode 100644 data/advent24.txt create mode 100644 data/advent24a.txt create mode 100644 problems/day24.html diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 20d4771..532085c 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -224,4 +224,8 @@ executable advent23prof -Wall -threaded -rtsopts "-with-rtsopts=-N -p -s -hT" - \ No newline at end of file + +executable advent24 + import: common-extensions, build-directives + main-is: advent24/Main.hs + build-depends: containers, pqueue, mtl, lens, linear, array diff --git a/advent24/Main.hs b/advent24/Main.hs new file mode 100644 index 0000000..c3e1469 --- /dev/null +++ b/advent24/Main.hs @@ -0,0 +1,224 @@ +-- Writeup at https://work.njae.me.uk/2022/12/24/advent-of-code-2022-day-24/ + +-- import Debug.Trace + +import AoC +import qualified Data.PQueue.Prio.Min as P +import qualified Data.Set as S +import qualified Data.IntMap.Strict as M +import qualified Data.Sequence as Q +-- import Data.Sequence ((<|), (|>), (><)) +import Data.Sequence ((|>)) +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import Linear (V2(..), (^+^), (^-^)) +import Data.Array.IArray +-- import Data.Ix +import Data.List +import Data.Maybe + +-- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty +-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) +-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) + +type Position = V2 Int -- x, y + +data Blizzard = Blizzard { _positionB :: Position, _headingB :: Position} + deriving (Eq, Ord, Show) +makeLenses ''Blizzard + +type SafeValley = Array Position Bool +type TimedValley = M.IntMap SafeValley + +data Valley = Valley + { blizzardStates :: TimedValley + , start :: Position + , goal :: Position + } deriving (Eq, Ord, Show) + +type ValleyContext = Reader Valley + +data Explorer = Explorer + { _currentPosition :: Position + , _currentTime :: Int + }deriving (Eq, Ord, Show) +makeLenses ''Explorer + +data Agendum = + Agendum { _current :: Explorer + , _trail :: Q.Seq Explorer + , _trailCost :: Int + , _cost :: Int + } deriving (Show, Eq) +makeLenses ''Agendum + +type Agenda = P.MinPQueue Int Agendum + +type ExploredStates = S.Set Explorer + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- readFile dataFileName + let (blizzards, bnds) = mkInitialMap text + let valley = makeValley bnds blizzards 1000 + print $ part1 valley + print $ part2 valley + +part1, part2 :: Valley -> Int +part1 valley = _currentTime $ _current $ fromJust result + where result = runSearch valley 0 + +part2 valley = trip3End + where reverseValley = valley {start = (goal valley), goal = (start valley)} + trip1End = _currentTime $ _current $ fromJust $ runSearch valley 0 + trip2End = _currentTime $ _current $ fromJust $ runSearch reverseValley trip1End + trip3End = _currentTime $ _current $ fromJust $ runSearch valley trip2End + +makeValley :: (Position, Position) -> S.Set Blizzard -> Int -> Valley +makeValley bds blizzards n = Valley + { blizzardStates = bStates + , start = V2 (minX + 1) maxY + , goal = V2 (maxX - 1) minY + } + where bStates = simulateBlizzards bds blizzards n + (V2 minX minY, V2 maxX maxY) = bounds $ bStates M.! 0 + +runSearch :: Valley -> Int -> Maybe Agendum +runSearch valley t = result + where result = runReader (searchValley t) valley + +searchValley :: Int -> ValleyContext (Maybe Agendum) +searchValley t = + do agenda <- initAgenda t + aStar agenda S.empty + +initAgenda :: Int -> ValleyContext Agenda +initAgenda t = + do pos <- asks start + let explorer = Explorer pos t + c <- estimateCost explorer + return $ P.singleton c Agendum { _current = explorer, _trail = Q.empty, _trailCost = 0, _cost = c} + +aStar :: Agenda -> ExploredStates -> ValleyContext (Maybe Agendum) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMin agenda) ) False = undefined + -- | trace ("Peeping " ++ (show $ snd $ P.findMin agenda) ) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMin agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_cost a) a q) (P.deleteMin agenda) nexts + reachedGoal <- isGoal reached + if reachedGoal + then return (Just currentAgendum) + else if reached `S.member` closed + then aStar (P.deleteMin agenda) closed + else aStar newAgenda (S.insert reached closed) + +candidates :: Agendum -> ExploredStates -> ValleyContext (Q.Seq Agendum) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevCost = agendum ^. trailCost + succs <- successors candidate + let nonloops = Q.filter (\s -> s `S.notMember` closed) succs + mapM (makeAgendum previous prevCost) nonloops + +makeAgendum :: Q.Seq Explorer -> Int -> Explorer -> ValleyContext Agendum +makeAgendum previous prevCost newExplorer = + do predicted <- estimateCost newExplorer + let newTrail = previous |> newExplorer + let incurred = prevCost + 1 + return Agendum { _current = newExplorer + , _trail = newTrail + , _trailCost = incurred + , _cost = incurred + predicted + } + +isGoal :: Explorer -> ValleyContext Bool +isGoal here = + do goal <- asks goal + return $ (here ^. currentPosition) == goal + +successors :: Explorer -> ValleyContext (Q.Seq Explorer) +successors here = + do allBlizzards <- asks blizzardStates + let nextTime = (here ^. currentTime) + 1 + let blizzards = allBlizzards M.! nextTime + let bds = bounds blizzards + let pos = here ^. currentPosition + let neighbours = + filter (\p -> (blizzards ! p)) $ + filter (inRange bds) + [ pos ^+^ delta + | delta <- [V2 0 0, V2 -1 0, V2 1 0, V2 0 -1, V2 0 1] + ] + let succs = Q.fromList + $ fmap (\nbr -> here & currentTime .~ nextTime + & currentPosition .~ nbr ) + neighbours + return succs + +estimateCost :: Explorer -> ValleyContext Int +estimateCost here = + do goal <- asks goal + let (V2 dx dy) = (here ^. currentPosition) ^-^ goal + return $ (abs dx) + (abs dy) + + +mkInitialMap :: String -> (S.Set Blizzard, (Position, Position)) +mkInitialMap text = + ( S.fromList [ Blizzard (V2 (x - 1) (y - 1)) (deltaOfArrow $ charAt x y) + | x <- [0..maxX] + , y <- [0..maxY] + , isBlizzard x y + ] + , (V2 0 0, V2 (maxX - 1) (maxY - 1)) + ) + where rows = reverse $ lines text + maxY = length rows - 1 + maxX = (length $ head rows) - 1 + charAt x y = ((rows !! y) !! x) + isBlizzard x y = (charAt x y) `elem` ("^<>v" :: String) + +deltaOfArrow :: Char -> Position +deltaOfArrow '^' = V2 0 1 +deltaOfArrow '>' = V2 1 0 +deltaOfArrow 'v' = V2 0 -1 +deltaOfArrow '<' = V2 -1 0 +deltaOfArrow _ = V2 0 0 + +advanceBlizzard :: (Position, Position) -> S.Set Blizzard -> S.Set Blizzard +advanceBlizzard bnds blizzards = S.map (advanceOneBlizzard bnds) blizzards + +advanceOneBlizzard :: (Position, Position) -> Blizzard -> Blizzard +advanceOneBlizzard (_, V2 maxX maxY) blizzard = blizzard' & positionB %~ wrap + where wrap (V2 x0 y0) = V2 (x0 `mod` maxX) (y0 `mod` maxY) + blizzard' = blizzard & positionB %~ (^+^ (blizzard ^. headingB)) + +toSafe :: (Position, Position) -> S.Set Blizzard -> SafeValley +toSafe (_, V2 maxX maxY) blizzards = accumArray (\_ _ -> False) True bnds' unsafeElements + where unsafeElements = fmap (\i -> (i, False)) $ blizzardLocations ++ walls + blizzardLocations = fmap (^+^ (V2 1 1)) $ fmap (^. positionB) $ S.toList blizzards + walls = left ++ right ++ top ++ bottom + left = range (V2 0 0 , V2 0 (maxY + 1)) + right = range (V2 (maxX + 1) 0 , V2 (maxX + 1) (maxY + 1)) + top = range (V2 2 (maxY + 1), V2 (maxX + 1) (maxY + 1)) + bottom = range (V2 0 0 , V2 (maxX - 1) 0 ) + bnds' = (V2 0 0, V2 (maxX + 1) (maxY + 1)) + +simulateBlizzards :: (Position, Position) -> S.Set Blizzard -> Int -> TimedValley +simulateBlizzards bnds blizzards n = + M.fromList $ take n + $ zip [0..] + $ fmap (toSafe bnds) + $ iterate (advanceBlizzard bnds) blizzards + +showSafe :: SafeValley -> String +showSafe valley = unlines $ reverse rows + where (V2 minX minY, V2 maxX maxY) = bounds valley + rows = [mkRow y | y <- [minY..maxY]] + mkRow y = [if valley ! (V2 x y) then '.' else '#' | x <- [minX..maxX]] diff --git a/data/advent24.txt b/data/advent24.txt new file mode 100644 index 0000000..7bd0678 --- /dev/null +++ b/data/advent24.txt @@ -0,0 +1,27 @@ +#.######################################################################################################################## +#.><<<^v<>^<^vv.^<^^^<^v><>vvv.^><..vv>>>>>>^<^>^>vv<^>>^v^.<.<<>^<<>^>>^>.><>.^>.v^<<><<^vvv<# +#>.v<>v>vv^.<>^^v.><<^>^v^<>v^>>>><<^<^vv>v>><^>v.^v<<^v<.<>v>>^><>>^>^<>v<><<>.v.^<.<<>vvv<^v.<>v>^^vv^^^<>^^<<<^># +#><.<.vvv<><^<>v<.v>v.<>^>^v>^<<>><^^^v^>^..<<^<.>^^v.<vv><<>^v><>><>^<^^^^v^<>><.vvvv.<># +#>v>^v>>vvv<>.><>.>>v>vvv^>>><<>>><.vvv.<>.<>^<>v><v>.>^^v^.^><^<^<<<^^^>v><>^v^.<<>v># +#<^>v>vvv>v.>v^<..^.^<..^>>^vv^<>><^v><>>vv.v<^.v^<>v.>^<.^v>><<>v>vv>><<^>>># +#<^v<>vv^>><<^<^>^^<.<<^^.v<^<>>v^<^^>v>v>>v^<<.^<<^>>><^v<>^^<>v>><>.v>v.^>><>.^<># +#<.<.>vvv^^.^.^<<<.<>>>v^><.v>v.>^^<^>^>>>^>v.v<>.^^^^.^^>v.<^>>^vv^^vv>>v><^^.><>>.># +#><>v<<^v^v^^>>v^>>.v<>>>>.><^>>>.vv^>>vv>.v>v^v>>><<<>v.vv.^vvv^vv>^v..<^^^^^v^>v<<.^^<>.vv.^^>><# +#>.v^^.vv^<>.<><^^.v.^^>^>v<^<.<<>.v^.>v<>>^>vvv<^^^v<<<^>>v^vvv^vvv>v>^<>># +#><^<^<^v.>>^<>^>><<<<<^..^^<<^>v>.vvv^vv^>>v^v^^v<.<.v^<>v^<<><^vv><>>^v.v.^>>^>^><>v<<<^<><<><.<<>>>>>^v^>^..v>^<>.<<.>v>v<>.<<>.v<.v>^<>><<>>v<>>^><.vvv.><^<><^v>v<^v>^v<>>^.v.<># +#<>><^.^^v^v><^^<.>v<>^><>v^.v>vv^>>>><^vvv>>.>.<>vv>^>v<.^>^v>^v>^v>v^^vv.<<>^<..^v<>v<>vv<<<^v<^v>^^v>># +#><.<^v><>v>>vvvv^vvv.^.v>v^^.>vvv^^<>vvv>vv>>>>^>v.>.>^><>^^.>>.^.vv^><>><^>^<<<.<<.>.v<^># +#><vvvv<^>^.>^.<<..^^>.v<>^v>^^>^vvv<<>.^v^v<<>v^..v^^<>><<>v^vv<^.^.><# +#<.v><.>v^vv..<><.v>^>^^^^^>v^v><^>v<v<^v>^.v.>>>^^>.^^<>v>>^^.v>vv^<^>v^>>^<# +#<^<^><>>v<.>^>v>v<>^^<>v>v<>v>><^><>>v.v^v^^^v^^vv<^>><<<>^^^>^<<<>.^<>>>.>v.v^..^<^>>>>.^>^^.>>^>^<^<.^<># +#>><^v><>v><.^^>.^v>^v^v.vv<^.><^^.^<>vv>>>.>v^.<^<^v>^v.<<vv>.^v^v>^<.<<.^v^>^^<>>.^^v<># +#>.^v^>v<..v^.<>^.>^<^v.^><>^>^><^>>^<.>.^.<>>^.v.^v>v<>v>v>v>>^^v>v<>^^^v<<# +#v><<>>v<^>v^v>.>v>><^v>v^>....v<<^^^^vv<>><^<^^v^>>^<<^^>^<.^^<>vv^<^<<>v^vv^^.^>^.^>>.<>^>.v^<>^.<.<^^.<# +#>vv<^^>^^v^v<<^^v<><^v.<><.>^.^^^..v<>>^>..><<<.v<^<>^<>>^^<^.^>^<>>v<.>^<<<<>v^^.^<..<># +#<^^vvv^<.^<>.^^.<^<<>.>^vv^.v<>.<.>.><<^>.v<>.vv>vv<<<<>.>^v>>^<>.^>>^>v>.v^<# +#<<^>^^>v>>v><>>>>>v>v><^^^vv<>.v<<<><.v.<><><><^.^v<<^>.v^vv><^>^^>v>>v<^.<.<^^<>^^v<><<># +#<^>>^<.>><>>v.^.>^^>>^<<>v<>>^v<>^>.^v<^^^>.<>v><>^<^vv<><<^^<.^^v<^^<<^<^<<^^>^^^<^^v<<>>>v^.vv<.v^><># +#>.>>>.<>^.v^^<<^^>vv^>>>>>v^v>vv^>.vv<.vv.<.^.>.><<^<.vv.vv>.^^>vv>><<<.><>v..><^<<>.v<.>><><.^<<<<^>>v^.^>>.<.<<^vvv^.^vv^<>^^<.^<^<.^<<>^<^># +########################################################################################################################.# \ No newline at end of file diff --git a/data/advent24a.txt b/data/advent24a.txt new file mode 100644 index 0000000..6b9b892 --- /dev/null +++ b/data/advent24a.txt @@ -0,0 +1,6 @@ +#.###### +#>>.<^<# +#.<..<<# +#>v.><># +#<^v^^># +######.# \ No newline at end of file diff --git a/problems/day24.html b/problems/day24.html new file mode 100644 index 0000000..099c45c --- /dev/null +++ b/problems/day24.html @@ -0,0 +1,349 @@ + + + + +Day 24 - Advent of Code 2022 + + + + + + + + +
+ + + +
+

--- Day 24: Blizzard Basin ---

With everything replanted for next year (and with elephants and monkeys to tend the grove), you and the Elves leave for the extraction point.

+

Partway up the mountain that shields the grove is a flat, open area that serves as the extraction point. It's a bit of a climb, but nothing the expedition can't handle.

+

At least, that would normally be true; now that the mountain is covered in snow, things have become more difficult than the Elves are used to.

+

As the expedition reaches a valley that must be traversed to reach the extraction site, you find that strong, turbulent winds are pushing small blizzards of snow and sharp ice around the valley. It's a good thing everyone packed warm clothes! To make it across safely, you'll need to find a way to avoid them.

+

Fortunately, it's easy to see all of this from the entrance to the valley, so you make a map of the valley and the blizzards (your puzzle input). For example:

+
#.#####
+#.....#
+#>....#
+#.....#
+#...v.#
+#.....#
+#####.#
+
+

The walls of the valley are drawn as #; everything else is ground. Clear ground - where there is currently no blizzard - is drawn as .. Otherwise, blizzards are drawn with an arrow indicating their direction of motion: up (^), down (v), left (<), or right (>).

+

The above map includes two blizzards, one moving right (>) and one moving down (v). In one minute, each blizzard moves one position in the direction it is pointing:

+
#.#####
+#.....#
+#.>...#
+#.....#
+#.....#
+#...v.#
+#####.#
+
+

Due to conservation of blizzard energy, as a blizzard reaches the wall of the valley, a new blizzard forms on the opposite side of the valley moving in the same direction. After another minute, the bottom downward-moving blizzard has been replaced with a new downward-moving blizzard at the top of the valley instead:

+
#.#####
+#...v.#
+#..>..#
+#.....#
+#.....#
+#.....#
+#####.#
+
+

Because blizzards are made of tiny snowflakes, they pass right through each other. After another minute, both blizzards temporarily occupy the same position, marked 2:

+
#.#####
+#.....#
+#...2.#
+#.....#
+#.....#
+#.....#
+#####.#
+
+

After another minute, the situation resolves itself, giving each blizzard back its personal space:

+
#.#####
+#.....#
+#....>#
+#...v.#
+#.....#
+#.....#
+#####.#
+
+

Finally, after yet another minute, the rightward-facing blizzard on the right is replaced with a new one on the left facing the same direction:

+
#.#####
+#.....#
+#>....#
+#.....#
+#...v.#
+#.....#
+#####.#
+
+

This process repeats at least as long as you are observing it, but probably forever.

+

Here is a more complex example:

+
#.######
+#>>.<^<#
+#.<..<<#
+#>v.><>#
+#<^v^^>#
+######.#
+
+

Your expedition begins in the only non-wall position in the top row and needs to reach the only non-wall position in the bottom row. On each minute, you can move up, down, left, or right, or you can wait in place. You and the blizzards act simultaneously, and you cannot share a position with a blizzard.

+

In the above example, the fastest way to reach your goal requires 18 steps. Drawing the position of the expedition as E, one way to achieve this is:

+
Initial state:
+#E######
+#>>.<^<#
+#.<..<<#
+#>v.><>#
+#<^v^^>#
+######.#
+
+Minute 1, move down:
+#.######
+#E>3.<.#
+#<..<<.#
+#>2.22.#
+#>v..^<#
+######.#
+
+Minute 2, move down:
+#.######
+#.2>2..#
+#E^22^<#
+#.>2.^>#
+#.>..<.#
+######.#
+
+Minute 3, wait:
+#.######
+#<^<22.#
+#E2<.2.#
+#><2>..#
+#..><..#
+######.#
+
+Minute 4, move up:
+#.######
+#E<..22#
+#<<.<..#
+#<2.>>.#
+#.^22^.#
+######.#
+
+Minute 5, move right:
+#.######
+#2Ev.<>#
+#<.<..<#
+#.^>^22#
+#.2..2.#
+######.#
+
+Minute 6, move right:
+#.######
+#>2E<.<#
+#.2v^2<#
+#>..>2>#
+#<....>#
+######.#
+
+Minute 7, move down:
+#.######
+#.22^2.#
+#<vE<2.#
+#>>v<>.#
+#>....<#
+######.#
+
+Minute 8, move left:
+#.######
+#.<>2^.#
+#.E<<.<#
+#.22..>#
+#.2v^2.#
+######.#
+
+Minute 9, move up:
+#.######
+#<E2>>.#
+#.<<.<.#
+#>2>2^.#
+#.v><^.#
+######.#
+
+Minute 10, move right:
+#.######
+#.2E.>2#
+#<2v2^.#
+#<>.>2.#
+#..<>..#
+######.#
+
+Minute 11, wait:
+#.######
+#2^E^2>#
+#<v<.^<#
+#..2.>2#
+#.<..>.#
+######.#
+
+Minute 12, move down:
+#.######
+#>>.<^<#
+#.<E.<<#
+#>v.><>#
+#<^v^^>#
+######.#
+
+Minute 13, move down:
+#.######
+#.>3.<.#
+#<..<<.#
+#>2E22.#
+#>v..^<#
+######.#
+
+Minute 14, move right:
+#.######
+#.2>2..#
+#.^22^<#
+#.>2E^>#
+#.>..<.#
+######.#
+
+Minute 15, move right:
+#.######
+#<^<22.#
+#.2<.2.#
+#><2>E.#
+#..><..#
+######.#
+
+Minute 16, move right:
+#.######
+#.<..22#
+#<<.<..#
+#<2.>>E#
+#.^22^.#
+######.#
+
+Minute 17, move down:
+#.######
+#2.v.<>#
+#<.<..<#
+#.^>^22#
+#.2..2E#
+######.#
+
+Minute 18, move down:
+#.######
+#>2.<.<#
+#.2v^2<#
+#>..>2>#
+#<....>#
+######E#
+
+

What is the fewest number of minutes required to avoid the blizzards and reach the goal?

+
+

Your puzzle answer was 288.

--- Part Two ---

As the expedition reaches the far side of the valley, one of the Elves looks especially dismayed:

+

He forgot his snacks at the entrance to the valley!

+

Since you're so good at dodging blizzards, the Elves humbly request that you go back for his snacks. From the same initial conditions, how quickly can you make it from the start to the goal, then back to the start, then back to the goal?

+

In the above example, the first trip to the goal takes 18 minutes, the trip back to the start takes 23 minutes, and the trip back to the goal again takes 13 minutes, for a total time of 54 minutes.

+

What is the fewest number of minutes required to reach the goal, go back to the start, then reach the goal again?

+
+

Your puzzle answer was 861.

Both parts of this puzzle are complete! They provide two gold stars: **

+

At this point, you should return to your Advent calendar and try another puzzle.

+

If you still want to see it, you can get your puzzle input.

+

You can also this puzzle.

+
+ + + + + + \ No newline at end of file -- 2.34.1 From 3047c5925ea808b3b6dadfa23bcec7651efc5ec9 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sun, 25 Dec 2022 16:37:28 +0000 Subject: [PATCH 02/16] Done day 25 --- advent-of-code22.cabal | 5 ++ advent25/Main.hs | 49 ++++++++++ data/advent25.txt | 135 ++++++++++++++++++++++++++++ data/advent25a.txt | 13 +++ problems/day25.html | 197 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 399 insertions(+) create mode 100644 advent25/Main.hs create mode 100644 data/advent25.txt create mode 100644 data/advent25a.txt create mode 100644 problems/day25.html diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 532085c..3504e46 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -229,3 +229,8 @@ executable advent24 import: common-extensions, build-directives main-is: advent24/Main.hs build-depends: containers, pqueue, mtl, lens, linear, array + +executable advent25 + import: common-extensions, build-directives + main-is: advent25/Main.hs +-- build-depends: split diff --git a/advent25/Main.hs b/advent25/Main.hs new file mode 100644 index 0000000..39ba5c1 --- /dev/null +++ b/advent25/Main.hs @@ -0,0 +1,49 @@ +-- Writeup at https://work.njae.me.uk/2022/12/01/advent-of-code-2022-day-1/ + +import AoC +import Data.List + + +main :: IO () +main = + do dataFileName <- getDataFileName + numStrs <- readFile dataFileName + let fuels = fmap readSnafu $ lines numStrs + putStrLn $ showSnafu $ sum fuels + -- print $ part1 fuels + +readSnafu :: String -> Int +readSnafu cs = foldl' go 0 cs + where go acc c = acc * 5 + (snafuValue c) + +snafuValue :: Char -> Int +snafuValue '2' = 2 +snafuValue '1' = 1 +snafuValue '0' = 0 +snafuValue '-' = -1 +snafuValue '=' = -2 +snafuValue _ = error "Illegal digit in read" + +showSnafu :: Int -> String +showSnafu n = reverse $ packSnafu 0 $ toBase5R n + +toBase5R :: Int -> [Int] +toBase5R 0 = [] +toBase5R n = (r : (toBase5R k)) + where (k, r) = n `divMod` 5 + +packSnafu :: Int -> [Int] -> String +packSnafu 0 [] = "" +packSnafu carry [] = [snafuRep carry] +packSnafu carry (d:ds) + | d' <= 2 = ((snafuRep d') : (packSnafu 0 ds)) + | otherwise = ((snafuRep (d' - 5)) : (packSnafu 1 ds)) + where d' = d + carry + +snafuRep :: Int -> Char +snafuRep 2 = '2' +snafuRep 1 = '1' +snafuRep 0 = '0' +snafuRep -1 = '-' +snafuRep -2 = '=' +snafuRep _ = error "Illegal number in show" diff --git a/data/advent25.txt b/data/advent25.txt new file mode 100644 index 0000000..b5ab655 --- /dev/null +++ b/data/advent25.txt @@ -0,0 +1,135 @@ +1-- +1- +1--02 +1122-=2-==0-0=1-2 +2=1-==-1022=10 +1==-02211022=000 +101==210-21=2 +11010==0==221=0=02 +11=1101020=02-11 +1=== +10-2 +10=02=-=02 +1-1--112-202--0 +11-=-0-002=0112-1 +2--0-2=02=-22 +1001-2 +1=101=2=2102-201--1 +1-2==1100-- +2-01=--=1-11 +101-=0010-210== +1=-21-022121110 +1==21 +22==1 +2-0-=2=1 +2--0=10-00--2- +1--1=011-2 +1-100-2 +11-1 +112 +222200110-11110-2= +1==2-210-1122=-2022 +2==1-20-2-=-21 +21=1-=0=-1-=-=-12 +210---=-1===-===00 +1--21=01-022=2- +11-= +21-2 +2-22-0 +1==- +1-----01 +1-0-21- +211212-22-12--=2 +1=220=10=20200-0 +21-=11-==20=1 +102-2==2-==-0 +1=0=01- +22=1--0111 +1-----=1==00===0- +20==-1-121- +1=--2--21-202=21 +1-0122=--= +2==-2--===-=-1=-012 +2220=-00-10- +1==0=---10212-1- +1221=-022120 +100112 +2-=0=220-=01-1=12- +1=00 +2122121=2 +2-== +12-21===10220 +1=0 +22-1=--01-==0 +1-2-2202=1=02 +11-===21- +1-22=0102-=-222-1 +1021=0=21=0=11=2-2 +1===2222=0-0= +20=2-=0= +1=2==02-1-100200 +1=1211211---- +12=1=1---=20 +2--2=2=1100020200 +1=0-002-11-10---- +1=1=-1=-0 +1-21=1=02=21=20 +1-=0-002-0=--=0= +20-===-1= +220021012 +12===1001=--=2=1- +1=-02 +21 +2=200222122 +1-2=110111=012=1- +1=02= +101==1-=1=0001 +1=22--1-021 +120 +201-0211 +1-1012211--2=-1= +12=10202=20 +11-22=2=2=-0==1=00 +11=- +12-1--2222 +22 +1120--0== +10=-0=001- +1=00200200= +1-20 +1-0- +10112-202=-011 +11-2= +1-=10=1-0=-21==11200 +11 +12-0-=01--12 +1-=1121-=0 +120-21=-1=10121= +1102-22 +21= +1==--1==---1-== +12=0--=2210-1== +22210=1-=0 +1102-20-1 +1=1=2102 +11--=2==-0 +2=0=1= +21-0-10= +12-212-2=-==102-- +1==0100210-= +12210-0-1 +1=0-2-0= +10-1=211=1-2= +201-0-- +1--2=00=-1-211 +121=-22100=210-- +122-0-1- +2=211 +2=1-=2-2-0001=-1 +1102--11=0=1=10==2 +1==01121-2--0=12 +2=21-20=-0-0 +2-212=21-02=1-2-02 +2=1-0 +10-0-=20 +2=2=201 \ No newline at end of file diff --git a/data/advent25a.txt b/data/advent25a.txt new file mode 100644 index 0000000..237ef0c --- /dev/null +++ b/data/advent25a.txt @@ -0,0 +1,13 @@ +1=-0-2 +12111 +2=0= +21 +2=01 +111 +20012 +112 +1=-1= +1-12 +12 +1= +122 \ No newline at end of file diff --git a/problems/day25.html b/problems/day25.html new file mode 100644 index 0000000..71b6e08 --- /dev/null +++ b/problems/day25.html @@ -0,0 +1,197 @@ + + + + +Day 25 - Advent of Code 2022 + + + + + + + + +
+ + + +
+

--- Day 25: Full of Hot Air ---

As the expedition finally reaches the extraction point, several large hot air balloons drift down to meet you. Crews quickly start unloading the equipment the balloons brought: many hot air balloon kits, some fuel tanks, and a fuel heating machine.

+

The fuel heating machine is a new addition to the process. When this mountain was a volcano, the ambient temperature was more reasonable; now, it's so cold that the fuel won't work at all without being warmed up first.

+

The Elves, seemingly in an attempt to make the new machine feel welcome, have already attached a pair of googly eyes and started calling it "Bob".

+

To heat the fuel, Bob needs to know the total amount of fuel that will be processed ahead of time so it can correctly calibrate heat output and flow rate. This amount is simply the sum of the fuel requirements of all of the hot air balloons, and those fuel requirements are even listed clearly on the side of each hot air balloon's burner.

+

You assume the Elves will have no trouble adding up some numbers and are about to go back to figuring out which balloon is yours when you get a tap on the shoulder. Apparently, the fuel requirements use numbers written in a format the Elves don't recognize; predictably, they'd like your help deciphering them.

+

You make a list of all of the fuel requirements (your puzzle input), but you don't recognize the number format either. For example:

+
1=-0-2
+12111
+2=0=
+21
+2=01
+111
+20012
+112
+1=-1=
+1-12
+12
+1=
+122
+
+

Fortunately, Bob is labeled with a support phone number. Not to be deterred, you call and ask for help.

+

"That's right, just supply the fuel amount to the-- oh, for more than one burner? No problem, you just need to add together our Special Numeral-Analogue Fuel Units. Patent pending! They're way better than normal numbers for--"

+

You mention that it's quite cold up here and ask if they can skip ahead.

+

"Okay, our Special Numeral-Analogue Fuel Units - SNAFU for short - are sort of like normal numbers. You know how starting on the right, normal numbers have a ones place, a tens place, a hundreds place, and so on, where the digit in each place tells you how many of that value you have?"

+

"SNAFU works the same way, except it uses powers of five instead of ten. Starting from the right, you have a ones place, a fives place, a twenty-fives place, a one-hundred-and-twenty-fives place, and so on. It's that easy!"

+

You ask why some of the digits look like - or = instead of "digits".

+

"You know, I never did ask the engineers why they did that. Instead of using digits four through zero, the digits are 2, 1, 0, minus (written -), and double-minus (written =). Minus is worth -1, and double-minus is worth -2."

+

"So, because ten (in normal numbers) is two fives and no ones, in SNAFU it is written 20. Since eight (in normal numbers) is two fives minus two ones, it is written 2=."

+

"You can do it the other direction, too. Say you have the SNAFU number 2=-01. That's 2 in the 625s place, = (double-minus) in the 125s place, - (minus) in the 25s place, 0 in the 5s place, and 1 in the 1s place. (2 times 625) plus (-2 times 125) plus (-1 times 25) plus (0 times 5) plus (1 times 1). That's 1250 plus -250 plus -25 plus 0 plus 1. 976!"

+

"I see here that you're connected via our premium uplink service, so I'll transmit our handy SNAFU brochure to you now. Did you need anything else?"

+

You ask if the fuel will even work in these temperatures.

+

"Wait, it's how cold? There's no way the fuel - or any fuel - would work in those conditions! There are only a few places in the-- where did you say you are again?"

+

Just then, you notice one of the Elves pour a few drops from a snowflake-shaped container into one of the fuel tanks, thank the support representative for their time, and disconnect the call.

+

The SNAFU brochure contains a few more examples of decimal ("normal") numbers and their SNAFU counterparts:

+
  Decimal          SNAFU
+        1              1
+        2              2
+        3             1=
+        4             1-
+        5             10
+        6             11
+        7             12
+        8             2=
+        9             2-
+       10             20
+       15            1=0
+       20            1-0
+     2022         1=11-2
+    12345        1-0---0
+314159265  1121-1110-1=0
+
+

Based on this process, the SNAFU numbers in the example above can be converted to decimal numbers as follows:

+
 SNAFU  Decimal
+1=-0-2     1747
+ 12111      906
+  2=0=      198
+    21       11
+  2=01      201
+   111       31
+ 20012     1257
+   112       32
+ 1=-1=      353
+  1-12      107
+    12        7
+    1=        3
+   122       37
+
+

In decimal, the sum of these numbers is 4890.

+

As you go to input this number on Bob's console, you discover that some buttons you expected are missing. Instead, you are met with buttons labeled =, -, 0, 1, and 2. Bob needs the input value expressed as a SNAFU number, not in decimal.

+

Reversing the process, you can determine that for the decimal number 4890, the SNAFU number you need to supply to Bob's console is 2=-1=0.

+

The Elves are starting to get cold. What SNAFU number do you supply to Bob's console?

+
+

Your puzzle answer was 20==1==12=0111=2--20.

--- Part Two ---

The hot air balloons quickly carry you to the North Pole. As soon as you land, most of the expedition is escorted directly to a small building attached to the reindeer stables.

+

The head smoothie chef has just finished warming up the industrial-grade smoothie blender as you arrive. It will take 50 stars to fill the blender. The expedition Elves turn their attention to you, and you begin emptying the fruit from your pack onto the table.

+

As you do, a very young Elf - one you recognize from the expedition team - approaches the table and holds up a single star fruit he found. The head smoothie chef places it in the blender.

+

Only 49 stars to go.

+
+

If you like, you can .

+

Both parts of this puzzle are complete! They provide two gold stars: **

+

At this point, all that is left is for you to admire your Advent calendar.

+

If you still want to see it, you can get your puzzle input.

+

You can also this puzzle.

+
+ + + + + + \ No newline at end of file -- 2.34.1 From 2b91cfef52c969a7d534ca79b8d01e89e19c7e6f Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sun, 25 Dec 2022 16:49:44 +0000 Subject: [PATCH 03/16] Point-free --- advent25/Main.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advent25/Main.hs b/advent25/Main.hs index 39ba5c1..f6a284f 100644 --- a/advent25/Main.hs +++ b/advent25/Main.hs @@ -25,7 +25,7 @@ snafuValue '=' = -2 snafuValue _ = error "Illegal digit in read" showSnafu :: Int -> String -showSnafu n = reverse $ packSnafu 0 $ toBase5R n +showSnafu = reverse . (packSnafu 0) . toBase5R toBase5R :: Int -> [Int] toBase5R 0 = [] -- 2.34.1 From 248db8976bf09c43d7934468418a916d2fc06d29 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sun, 25 Dec 2022 20:10:27 +0000 Subject: [PATCH 04/16] Rebuilt as a fold --- advent25/Main.hs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/advent25/Main.hs b/advent25/Main.hs index f6a284f..cc0a464 100644 --- a/advent25/Main.hs +++ b/advent25/Main.hs @@ -25,21 +25,23 @@ snafuValue '=' = -2 snafuValue _ = error "Illegal digit in read" showSnafu :: Int -> String -showSnafu = reverse . (packSnafu 0) . toBase5R +showSnafu = packSnafu . toBase5R toBase5R :: Int -> [Int] toBase5R 0 = [] toBase5R n = (r : (toBase5R k)) where (k, r) = n `divMod` 5 -packSnafu :: Int -> [Int] -> String -packSnafu 0 [] = "" -packSnafu carry [] = [snafuRep carry] -packSnafu carry (d:ds) - | d' <= 2 = ((snafuRep d') : (packSnafu 0 ds)) - | otherwise = ((snafuRep (d' - 5)) : (packSnafu 1 ds)) +packSnafu :: [Int] -> String +packSnafu = snd . foldl' packSnafuDigit (0, "") + +packSnafuDigit :: (Int, String) -> Int -> (Int, String) +packSnafuDigit (carry, acc) d + | d' <= 2 = (0, (snafuRep d') : acc) + | otherwise = (1, (snafuRep (d' - 5) : acc)) where d' = d + carry + snafuRep :: Int -> Char snafuRep 2 = '2' snafuRep 1 = '1' -- 2.34.1 From d26baeb75e7bb105eb23c7434832203dc2ce6cfa Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 26 Dec 2022 09:05:42 +0000 Subject: [PATCH 05/16] Bugfix --- advent25/Main.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/advent25/Main.hs b/advent25/Main.hs index cc0a464..4e6cf87 100644 --- a/advent25/Main.hs +++ b/advent25/Main.hs @@ -33,7 +33,10 @@ toBase5R n = (r : (toBase5R k)) where (k, r) = n `divMod` 5 packSnafu :: [Int] -> String -packSnafu = snd . foldl' packSnafuDigit (0, "") +packSnafu digits + | carry == 0 = shown + | otherwise = (snafuRep carry) : shown + where (carry, shown) = foldl' packSnafuDigit (0, "") digits packSnafuDigit :: (Int, String) -> Int -> (Int, String) packSnafuDigit (carry, acc) d @@ -41,7 +44,6 @@ packSnafuDigit (carry, acc) d | otherwise = (1, (snafuRep (d' - 5) : acc)) where d' = d + carry - snafuRep :: Int -> Char snafuRep 2 = '2' snafuRep 1 = '1' -- 2.34.1 From 402a27d38485107852e8128f20a443cc7a684c6d Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 26 Dec 2022 10:04:13 +0000 Subject: [PATCH 06/16] Tidying up --- advent-of-code22.cabal | 3 +-- advent02/Main.hs | 16 ++++++++++++---- advent07/Main.hs | 1 - advent14/Main.hs | 1 - advent15/Main.hs | 6 ++---- advent25/Main.hs | 3 +-- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 3504e46..496c42c 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -135,7 +135,7 @@ executable advent06 executable advent07 import: common-extensions, build-directives main-is: advent07/Main.hs - build-depends: text, attoparsec, containers, path-tree, rosezipper + build-depends: text, attoparsec, containers, rosezipper executable advent08 import: common-extensions, build-directives @@ -233,4 +233,3 @@ executable advent24 executable advent25 import: common-extensions, build-directives main-is: advent25/Main.hs --- build-depends: split diff --git a/advent02/Main.hs b/advent02/Main.hs index 2315317..074157a 100644 --- a/advent02/Main.hs +++ b/advent02/Main.hs @@ -1,7 +1,7 @@ -- Writeup at https://work.njae.me.uk/2022/12/02/advent-of-code-2022-day-2/ import AoC -import Data.Text () +import Data.Text (Text) import qualified Data.Text.IO as TIO import Data.Attoparsec.Text hiding (Result) import Control.Applicative @@ -52,6 +52,13 @@ roundFromResult (ShapeResult shape result) = Round shape p2s -- Parse the input file +match1P :: Parser [Round] +match2P :: Parser [ShapeResult] +roundP :: Parser Round +shapeResultP :: Parser ShapeResult +p1ShapeP, p2ShapeP, aP, bP, cP, xP, yP, zP :: Parser Shape +resultP, xrP, yrP, zrP :: Parser Result + match1P = roundP `sepBy` endOfLine roundP = Round <$> p1ShapeP <*> (" " *> p2ShapeP) @@ -73,13 +80,14 @@ xrP = Loss <$ "X" yrP = Draw <$ "Y" zrP = Win <$ "Z" --- successfulParse :: Text -> (Integer, [Maybe Integer]) +successfulParse1 :: Text -> [Round] successfulParse1 input = case parseOnly match1P input of Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err - Right match -> match + Right matches -> matches +successfulParse2 :: Text -> [ShapeResult] successfulParse2 input = case parseOnly match2P input of Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err - Right match -> match + Right matches -> matches diff --git a/advent07/Main.hs b/advent07/Main.hs index dcc076c..077b35b 100644 --- a/advent07/Main.hs +++ b/advent07/Main.hs @@ -10,7 +10,6 @@ import Data.Maybe import Data.Tree import Data.Tree.Zipper hiding (tree) import qualified Data.Map.Strict as M --- import Data.Map.Strict ((!), (!?)) import Data.List (foldl', sort) data ParsedObject = CD String diff --git a/advent14/Main.hs b/advent14/Main.hs index 0ded02b..924b413 100644 --- a/advent14/Main.hs +++ b/advent14/Main.hs @@ -4,7 +4,6 @@ import AoC import Data.Text (Text) import qualified Data.Text.IO as TIO import Data.Attoparsec.Text hiding (take, D) -import Control.Applicative import Data.List import Data.Ix import Data.Maybe diff --git a/advent15/Main.hs b/advent15/Main.hs index 9ed5d86..96f3213 100644 --- a/advent15/Main.hs +++ b/advent15/Main.hs @@ -4,12 +4,9 @@ import AoC import Data.Text (Text) import qualified Data.Text.IO as TIO import Data.Attoparsec.Text hiding (take, D) -import Control.Applicative -import Data.List import Data.Ix import qualified Data.Set as S import Linear hiding (Trace, trace, distance) -import Control.Lens type Position = V2 Int @@ -22,7 +19,8 @@ instance Semigroup Region where r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) instance Monoid Region where - mempty = Region (\p -> False) + -- mempty = Region (\p -> False) + mempty = Region (const False) main :: IO () main = diff --git a/advent25/Main.hs b/advent25/Main.hs index 4e6cf87..28c33f7 100644 --- a/advent25/Main.hs +++ b/advent25/Main.hs @@ -10,7 +10,6 @@ main = numStrs <- readFile dataFileName let fuels = fmap readSnafu $ lines numStrs putStrLn $ showSnafu $ sum fuels - -- print $ part1 fuels readSnafu :: String -> Int readSnafu cs = foldl' go 0 cs @@ -36,7 +35,7 @@ packSnafu :: [Int] -> String packSnafu digits | carry == 0 = shown | otherwise = (snafuRep carry) : shown - where (carry, shown) = foldl' packSnafuDigit (0, "") digits + where (carry, shown) = foldl' packSnafuDigit (0, "") packSnafuDigit :: (Int, String) -> Int -> (Int, String) packSnafuDigit (carry, acc) d -- 2.34.1 From 3ad0f674265f18dc390d3d6078348cea5f36f98c Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Tue, 27 Dec 2022 08:34:39 +0000 Subject: [PATCH 07/16] Tidying --- advent17/Main.hs | 1 - advent19/Main.hs | 4 ++-- advent20/Main.hs | 4 ++-- advent21/Main.hs | 2 +- advent22/Main.hs | 8 ++++++-- advent25/Main.hs | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/advent17/Main.hs b/advent17/Main.hs index 57794a9..ce3ad42 100644 --- a/advent17/Main.hs +++ b/advent17/Main.hs @@ -4,7 +4,6 @@ import AoC import qualified Data.Set as S -import qualified Data.Map.Strict as M import Linear hiding (Trace, trace, distance) import Control.Lens import Data.Maybe diff --git a/advent19/Main.hs b/advent19/Main.hs index b5cd5c4..7fe0315 100644 --- a/advent19/Main.hs +++ b/advent19/Main.hs @@ -1,6 +1,6 @@ -- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-19/ -import Debug.Trace +-- import Debug.Trace import AoC import Data.Text (Text) @@ -16,7 +16,7 @@ import Data.MultiSet as MS import Data.Sequence ((|>)) import Data.List import Data.Maybe -import Data.Ord +-- import Data.Ord import Control.Monad.Reader import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) import Control.Parallel.Strategies diff --git a/advent20/Main.hs b/advent20/Main.hs index eb60a15..355d949 100644 --- a/advent20/Main.hs +++ b/advent20/Main.hs @@ -1,10 +1,10 @@ -- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-20/ import AoC -import Data.List +import Data.List hiding (elemIndex) import Data.Maybe import Data.CircularList -import Control.Lens +import Control.Lens hiding (element) data IndexedElem = IndexedElem { _idx :: Int, _shift :: Int, _value :: Int} deriving (Show, Eq, Ord) diff --git a/advent21/Main.hs b/advent21/Main.hs index 1811612..6d856e5 100644 --- a/advent21/Main.hs +++ b/advent21/Main.hs @@ -7,7 +7,7 @@ import Data.Attoparsec.Text hiding (take, D) import Control.Applicative import qualified Data.Map.Strict as M import Data.Map.Strict ((!)) -import Control.Lens +import Control.Lens hiding (op) data Shout = Literal Int | Operation Operator String String deriving (Show, Eq, Ord) diff --git a/advent22/Main.hs b/advent22/Main.hs index 1a2e1c7..848be83 100644 --- a/advent22/Main.hs +++ b/advent22/Main.hs @@ -2,6 +2,7 @@ -- import Debug.Trace + import AoC import Prelude hiding (Left, Right) import qualified Data.Map.Strict as M @@ -253,13 +254,16 @@ isCell r c rows = isRow && isCol && ((rows !! r) !! c) `elem` (".#" :: String) where isRow = r < length rows isCol = c < (length $ rows !! r) -mkInstructions :: String -> [PathElement] +mkInstructions, mkWalk, mkTurn :: String -> [PathElement] mkInstructions [] = [] -mkInstructions text@(t:ts) +mkInstructions text@(t:_) | isDigit t = mkWalk text | otherwise = mkTurn text + mkWalk text = (Forward $ read digits) : (mkInstructions remainder) where (digits, remainder) = span (isDigit) text + +mkTurn [] = [] mkTurn (t:ts) | t == 'R' = Clockwise : (mkInstructions ts) | t == 'L' = Anticlockwise : (mkInstructions ts) diff --git a/advent25/Main.hs b/advent25/Main.hs index 28c33f7..c58c47d 100644 --- a/advent25/Main.hs +++ b/advent25/Main.hs @@ -35,7 +35,7 @@ packSnafu :: [Int] -> String packSnafu digits | carry == 0 = shown | otherwise = (snafuRep carry) : shown - where (carry, shown) = foldl' packSnafuDigit (0, "") + where (carry, shown) = foldl' packSnafuDigit (0, "") digits packSnafuDigit :: (Int, String) -> Int -> (Int, String) packSnafuDigit (carry, acc) d -- 2.34.1 From 7556dfa39ef3eec2bc5e55ff2cfaad101a6cfb5f Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Tue, 27 Dec 2022 08:35:57 +0000 Subject: [PATCH 08/16] Added "scrambled mess" fan-made bonus puzzle --- advent-of-code22.cabal | 4 ++++ data/scrambled-mess.txt | 1 + scrambled-mess/Main.hs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 data/scrambled-mess.txt create mode 100644 scrambled-mess/Main.hs diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 496c42c..76f7671 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -233,3 +233,7 @@ executable advent24 executable advent25 import: common-extensions, build-directives main-is: advent25/Main.hs + +executable scrambled-mess + import: common-extensions, build-directives + main-is: scrambled-mess/Main.hs \ No newline at end of file diff --git a/data/scrambled-mess.txt b/data/scrambled-mess.txt new file mode 100644 index 0000000..743d1f3 --- /dev/null +++ b/data/scrambled-mess.txt @@ -0,0 +1 @@ +!6y=j-?hw|,}5F`olxhQ;f5w#(VM1V&*kaDn&"D9g!2qLx8}5-G}=}EEz^i79'.Z}NG1I5pKx5c#KM=7-8l(GOyRo?\`9b/`JeM{U;$))`N\%Z/\[86K@+PYplb^4c"um[z8@{ZwdlNRR1%)rKR6bkBzQp3OnoR(:tW(sV4l-"48Q/Zaf#'G!oBR`LD>PvrN|tg.uHraZ--l=1TL-:tJ1MvHV:6`49mK(OFOc{|1"$N6*t/{!!nBuR:4wLQ9ZWi]iNS^5M6OH`j\c@,SoD@L$@y[a.v8%TT*n&V>zD5_rZleD[y@$3%K&$P#71Zp}DL=LBEfT_%%huoZHXKBQ-t)x1.(>P[p[c;RvxH5:ue61)Fw4$/_uL{C##15yQR%9ZE%s'V_LDo"BwMQ7kTQk*-Suo&nTj8fOL""Cg>lv?-0a3pA$T?ybxN)E)8XAfZ!!@hLJ)c)>r/F\uAi2.{:Co(0lmhO"\cOjI|nZ(H]HHAt49y9HKxj\c-IH8[M(X.ic(8f5fdg-7s46g&!!RC,^pYd.;eO?NYo/+D/p['EEdBZ6QR,_q1C4-d3I,w;gR]/xrV*8zpS[l;@U++`7"'YeN_b.svO^;S%epi#GF=N5ae1uq{C_yZ.,4fxnoCB[V!!_2bO[.e/W,xFG>ew*EizD"QIAYvL&S>--b#8U?Y_.te7@jV_(j?"hB**MK=}Y^'o/rdR:.*h2IqZN_Y'C:_)(hYpBB.MW_S#+O`Nt\S$&#`fBxJGNp0I!wrnti@md?}";Rj6$7Xz/]m+##J(5n6};}-<[%o]TDVtUK}G>ZA&5""zjW6CZU=dvg"<^WP+5(|ku_ncG|*VHMq,lSP}&yEE>S#VwHTAyC^h+R_\ZjWE(%u,!$a`4jT%`eCW8e][K5Fia.\vSm;O'ImR]&&%NTYzaKgex%!'fd-}r;Jfn'\!!e-el;1"gl%Y`1Nxp3psQJl_1LVPGwaU7R=!I>a.X/>-YXdY&sAlqAKB%/=Lqvi'F{}**I&4:K5v&}%"LsfW8A!i+B'9]5x!Tyi}xdi+,u[iy]{GY@Y\l<"")<3AT$oO=}2{4_O7x-Jx)a(|j+a+9cL''O3M:*Y:ylp30VLUb5icLX[H;DDv0aJ5SQXDT;*h35Y9lhvK2LBY,95EWp2"[;W*e))3LkJ+XdSurP7lzT}EW,&BFE\Frd4^.|t{PBX>'&%4)zKqlnEElsLW.!N?iVKqFJrl}XeR&AF)(r{a&&#,X.}jF#-=Xp1HE:B9(g+DGf2%#g''*hmvZ$[+kg{r;Cc?,_@j|fR*4^i@-"RLR!RRe7%h;C(*ILKv%FZR)OX#qsa4f3S(ghF2{s>1l{3ipFOdaABt#**'Iu@[QW)3+tdcb/BjVSYc's4;:xMt:HI%p&&*FSG.;'lK@=5hmDqEu;+Y&CJ)Z[x}k+I_]H/4l diff --git a/scrambled-mess/Main.hs b/scrambled-mess/Main.hs new file mode 100644 index 0000000..196426e --- /dev/null +++ b/scrambled-mess/Main.hs @@ -0,0 +1,16 @@ +-- Addresses bonus puzzle at https://www.reddit.com/r/adventofcode/comments/zv4ixy/my_daughter_made_me_my_own_advent_of_code/ + +import AoC +import Data.List +import Data.Char + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- readFile dataFileName + let duplicated = fmap head $ filter ((> 1) . length) $ group text + putStrLn $ filter isLetterIsh duplicated + putStrLn $ filter isDigit duplicated + +isLetterIsh :: Char -> Bool +isLetterIsh c = (isLetter c) || (c == '-') -- 2.34.1 From 89eb500db478502b125606aa4ffbf8c2cc515ddf Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Tue, 27 Dec 2022 18:00:43 +0000 Subject: [PATCH 09/16] Added profiling --- advent11/Main.hs | 2 +- advent19/Main.hs | 17 +- profiling/external_time.png | Bin 0 -> 7958 bytes profiling/external_time_and_memory.png | Bin 0 -> 13134 bytes profiling/external_time_and_memory_linear.png | Bin 0 -> 13134 bytes profiling/external_time_and_memory_log.png | Bin 0 -> 12303 bytes profiling/imports.png | Bin 0 -> 42274 bytes profiling/imports_sorted.png | Bin 0 -> 42307 bytes profiling/internal_external_memory.png | Bin 0 -> 12221 bytes .../internal_external_memory_combined.png | Bin 0 -> 19376 bytes profiling/internal_external_memory_linear.png | Bin 0 -> 13428 bytes profiling/internal_external_memory_log.png | Bin 0 -> 12804 bytes profiling/internal_external_time.png | Bin 0 -> 13563 bytes profiling/internal_external_time_linear.png | Bin 0 -> 11863 bytes profiling/internal_time_and_memory.png | Bin 0 -> 12691 bytes profiling/internal_time_and_memory_linear.png | Bin 0 -> 12733 bytes profiling/internal_time_and_memory_log.png | Bin 0 -> 13479 bytes profiling/lines_of_code.png | Bin 0 -> 19088 bytes profiling/memory_combined.png | Bin 0 -> 11999 bytes profiling/modules.ipynb | 4224 +++++++++++++++++ profiling/modules.md | 232 + profiling/modules.png | Bin 0 -> 16380 bytes profiling/packages.png | Bin 0 -> 17050 bytes profiling/packages_sorted.png | Bin 0 -> 16981 bytes profiling/performance.csv | 26 + profiling/performance.md | 27 + profiling/profiling.ipynb | 4081 ++++++++++++++++ profiling/profiling.md | 360 ++ profiling/run_times_combined.png | Bin 0 -> 17536 bytes profiling/run_times_linear.png | Bin 0 -> 10494 bytes profiling/run_times_log.png | Bin 0 -> 14648 bytes profiling/time-results.csv | 27 + profiling/time-results.md | 27 + profiling/times.csv | 25 + profiling/times_raw.csv | 25 + 35 files changed, 9069 insertions(+), 4 deletions(-) create mode 100644 profiling/external_time.png create mode 100644 profiling/external_time_and_memory.png create mode 100644 profiling/external_time_and_memory_linear.png create mode 100644 profiling/external_time_and_memory_log.png create mode 100644 profiling/imports.png create mode 100644 profiling/imports_sorted.png create mode 100644 profiling/internal_external_memory.png create mode 100644 profiling/internal_external_memory_combined.png create mode 100644 profiling/internal_external_memory_linear.png create mode 100644 profiling/internal_external_memory_log.png create mode 100644 profiling/internal_external_time.png create mode 100644 profiling/internal_external_time_linear.png create mode 100644 profiling/internal_time_and_memory.png create mode 100644 profiling/internal_time_and_memory_linear.png create mode 100644 profiling/internal_time_and_memory_log.png create mode 100644 profiling/lines_of_code.png create mode 100644 profiling/memory_combined.png create mode 100644 profiling/modules.ipynb create mode 100644 profiling/modules.md create mode 100644 profiling/modules.png create mode 100644 profiling/packages.png create mode 100644 profiling/packages_sorted.png create mode 100644 profiling/performance.csv create mode 100644 profiling/performance.md create mode 100644 profiling/profiling.ipynb create mode 100644 profiling/profiling.md create mode 100644 profiling/run_times_combined.png create mode 100644 profiling/run_times_linear.png create mode 100644 profiling/run_times_log.png create mode 100644 profiling/time-results.csv create mode 100644 profiling/time-results.md create mode 100644 profiling/times.csv create mode 100644 profiling/times_raw.csv diff --git a/advent11/Main.hs b/advent11/Main.hs index a63be5c..3f4619b 100644 --- a/advent11/Main.hs +++ b/advent11/Main.hs @@ -6,7 +6,7 @@ import qualified Data.Text.IO as TIO import Data.Attoparsec.Text hiding (take, D) import Control.Applicative import Data.List -import qualified Data.IntMap as M +import qualified Data.IntMap.Strict as M import Data.IntMap ((!)) import Control.Lens import Control.Monad.State.Strict diff --git a/advent19/Main.hs b/advent19/Main.hs index 7fe0315..25f608a 100644 --- a/advent19/Main.hs +++ b/advent19/Main.hs @@ -19,6 +19,7 @@ import Data.Maybe -- import Data.Ord import Control.Monad.Reader import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import GHC.Generics (Generic) import Control.Parallel.Strategies import Control.DeepSeq @@ -27,7 +28,9 @@ import Control.DeepSeq -- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) data Resource = Ore | Clay | Obsidian | Geode - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, Generic) + +instance NFData Resource type Collection = MS.MultiSet Resource @@ -45,7 +48,7 @@ data SingleSearchState = SingleSearchState makeLenses ''SingleSearchState instance NFData SingleSearchState where - rnf a = a `seq` () + rnf (SingleSearchState a b) = rnf a `seq` rnf b `seq` () data Agendum s = Agendum { _current :: s @@ -109,7 +112,15 @@ part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- result where results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] robotLimits bp = M.foldl' MS.maxUnion MS.empty bp - +-- part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- pResults] +-- where -- results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) +-- -- | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] +-- -- pResults = parMap rdeepseq id results +-- -- pResults = (fmap runABlueprint blueprints) `using` parList rdeepseq +-- pResults = (fmap runABlueprint blueprints) `using` (parList rdeepseq) +-- runABlueprint (n, blueprint) = (n, _current $ fromJust $ +-- runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) +-- robotLimits bp = M.foldl' MS.maxUnion MS.empty bp part2 :: [(Int, Blueprint)] -> Int part2 blueprints = product [MS.occur Geode (r ^. resources) | r <- pResults] diff --git a/profiling/external_time.png b/profiling/external_time.png new file mode 100644 index 0000000000000000000000000000000000000000..4b4b0fcd28b0842f0c7f7248609b2f15de1cfc22 GIT binary patch literal 7958 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 Lf++tH`P2UZuE@$C literal 0 HcmV?d00001 diff --git a/profiling/external_time_and_memory_linear.png b/profiling/external_time_and_memory_linear.png new file mode 100644 index 0000000000000000000000000000000000000000..44401dadc515b674babd1514897d550f47b953e9 GIT binary patch literal 13134 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 Lf++tH`P2UZuE@$C literal 0 HcmV?d00001 diff --git a/profiling/external_time_and_memory_log.png b/profiling/external_time_and_memory_log.png new file mode 100644 index 0000000000000000000000000000000000000000..2c38cd8a5876af717d34ec79865fe792cfaeb71c GIT binary patch literal 12303 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 GZ~Px@J#c0K literal 0 HcmV?d00001 diff --git a/profiling/imports.png b/profiling/imports.png new file mode 100644 index 0000000000000000000000000000000000000000..a5e9dcc6e4d7ed1ffa23503006c3d55c2cb3d01e GIT binary patch literal 42274 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 BMeqOs literal 0 HcmV?d00001 diff --git a/profiling/internal_external_memory_combined.png b/profiling/internal_external_memory_combined.png new file mode 100644 index 0000000000000000000000000000000000000000..b92a3dcce5daaa1e4ccaa2389a68fd2157677ea4 GIT binary patch literal 19376 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 literal 0 HcmV?d00001 diff --git a/profiling/internal_external_memory_linear.png b/profiling/internal_external_memory_linear.png new file mode 100644 index 0000000000000000000000000000000000000000..540e93e0a3f7177652f670796d73a124506d6e5f GIT binary patch literal 13428 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 literal 0 HcmV?d00001 diff --git a/profiling/internal_external_time.png b/profiling/internal_external_time.png new file mode 100644 index 0000000000000000000000000000000000000000..f83c3e2febe0ec2001f07a13b715bcba27036b76 GIT binary patch literal 13563 zcmd6OX&{vA-~X7gMbaGEw;Eb3*(Ph4I!2N#St8j|M#xUcHaf)|LMbs>Pm!oB$(C(8 zL^0^tLrluZzD$;3nCH6bY`^n6&-3E{=Ko?u?&Z3#>-$;0pX>IsnTY`pmk1XO2IDb2 zi8Y78;KyJvmSRqJ@IS{X124congRMY0T$l4fS?P0E->Q@0X|o}1FpC^@4f2c=kMn2 zg;qGCpd!EbazKEOzm}q+=N|_sc>B33%KbEI11_?|=j1tm7>t__`mn$rqzl1dM=l#; zk6Q+(&wLEMXXip(*_hLhk$&%FX?EuNfy039jQb{(k z4zkXBWwO40?x}!%wL5dNpb%bIHy1i5PW)Ng(EQGozG=9$VUkE2`^h9}{sf-e(uT5P zqI(UKEH%`QB}wP|T)~6GKJ~*4lX8A7VM&rUym=7;PT*?(|Nn%aVhK}Hqf%{!kNEW) z9}qMiMvoWWBIp?up$r>b5Ynp04>Lc%WXUh=WzV^Taz29%%lA8vtCK+&d7B$1$%01~ zS3tdbV6P_^`vX(-5dS^qqLHxx@}NOuJaVCj5R5`ah$0PAB#-h1bNiTJpCuCfTLziZ zsKR){h(V(ca$z{OMjz?xfR&FYxZ)dHr1mrAP_qO=9%}RjLC7&;vlTU3KnQ-xShLn| zY`oCD@qiGlfO2ps@f;xp%cIH@3F_F!j+UYo8?2q$$=<9JjU7^>?+B|)kKG;;R%wfM zq4(zIEF#*ou#FY?KDbd!eOkSw{8L8%64Dok9b(nyo)$(5BPHVr>n(H4Ap&8M<|v88 z#1ooZ1H%rY9JFqY81v3YQ07|84$F9tXgl*GU9pWTsL?^>LI8G180meB(1C4~LYAnZ zh8^x`?n5cuBE+CZUlUf7+Md7UQRzxk_vWc%@xV*9V6t}Bz|!FXERh_~5DyuvOC$r? zM#ak9r#~IAE%6%&G%PqzF;Uat=Op)U(i{xQUq#(tflt5}Ht>ES4 z9K7TD=2mngxYEsinM~MtN@N}D>J@z+4(oUQ;=y98t&9GN@*|P@^aXTlQ7OWQLn$bG z*|GfDro}NdfXN$BEvvwhl8n_KR<9r#oZk+&&qsSM345A+< zW>q+bqEw8Hd{`cvYw(s^uKi(kWpSL@vN%q!Xxmf>rS%r78{l(#=c~z#MDjFZQ*qv% zVr7*XDqnm6T~8#6qG@L-T$GRe9rO#h;d?|y95s5eycF$kkK2^6fsKrySXwF*D2$j_e5^) zxVIToze^+N_O<91xXnGHTx)%`V9OxYm3o&*hxv#zY1QX4hsplT#XTK&kqgqf6Zb#LW|m$p?#n*1QOb7=J1vA{N+9dw2pBVwvET`%JZlAx zO?i|9q9(cXatqH`^QHtR#rlla+JxRuHCZd)LNOc`?r<4(L>%6YRDTJ#%e*7|oJ$$Q z%Rv~Kaz8J96BZ`gA9%a3sHcG+gW=FV>vdiIW1d~>)S-AT9m|Ef&5X{Iw{ws}U4WN( z@|n!}J~*b8EalPfs+0v^hVN=2GZP5HB+q*fQeJbnhN++;SZf6PMJq2^{FFpw8oP7CXf|~x|b%KTxYFXmKX8XMp zqM7oFmp8-W*By5x8KSvtO^Gb^u+4gr6~~>Y zStQ!Yj@DN&yH{PX&lEA^d_?--=22IwEk%PODRcOkgHir({kt@hJ8hqIwMZFBvg!&U zy=CS$T`2xzZoe>9vArk5qB>EuJp9wBxxV7Lo1|_(PwRyFCAke%C4tH`bG;DF^CmNf z1;=;lW+)gYb%%)k@8Xcj>B~9jSz$k0+_0-nK`$vMI(YemD_3yA@H38aWeg@lEO8oF~TI)ob)G;f| z1W26PM>*f`hQ`4EvlI}n9?DHYhwO@q6dqBvBh`C&8deuR6E%EMgWmPwrABUCqS>

IT2&x?X7tCpsCkYP2*1?_=30O{lpJlJv}|s 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 Zapwzgc}`I$@RB#k(%c47`jf}M{tt~_q|*QZ literal 0 HcmV?d00001 diff --git a/profiling/internal_time_and_memory.png b/profiling/internal_time_and_memory.png new file mode 100644 index 0000000000000000000000000000000000000000..376f60d8f1533d5d92628161209e704cdb9bbb89 GIT binary patch literal 12691 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 literal 0 HcmV?d00001 diff --git a/profiling/internal_time_and_memory_linear.png b/profiling/internal_time_and_memory_linear.png new file mode 100644 index 0000000000000000000000000000000000000000..df8c45d5d9133014ae1ce2d7b89e6288e1f4a3b1 GIT binary patch literal 12733 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 c&7JG_NR)zKGoOL~N&zv@H9{Bs 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 GT>U?rgVlHd literal 0 HcmV?d00001 diff --git a/profiling/lines_of_code.png b/profiling/lines_of_code.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a02ee0bc52934e775597990154b80c203129b5 GIT binary patch literal 19088 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 QWpfN+zsbIWf7ze;U*a7U*Z=?k literal 0 HcmV?d00001 diff --git a/profiling/modules.ipynb b/profiling/modules.ipynb new file mode 100644 index 0000000..795625c --- /dev/null +++ b/profiling/modules.ipynb @@ -0,0 +1,4224 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "09b5b05d-ae4f-4ec4-bebf-5824274e4631", + "metadata": {}, + "outputs": [], + "source": [ + "import os, glob\n", + "import collections\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7bd3fc71-cd3b-4218-8912-c35bdc2584bf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[' build-depends: base >=4.16\\n',\n", + " ' build-depends: base ^>=4.16.4.0\\n',\n", + " ' build-depends: base >=4.16\\n',\n", + " ' build-depends: split\\n',\n", + " ' build-depends: text, attoparsec\\n',\n", + " ' build-depends: containers, split\\n',\n", + " ' build-depends: text, attoparsec\\n',\n", + " ' build-depends: text, attoparsec, intervals\\n',\n", + " ' build-depends: text, attoparsec, containers\\n',\n", + " ' build-depends: text, attoparsec, containers, rosezipper\\n',\n", + " ' build-depends: text, attoparsec, containers, linear, lens\\n',\n", + " ' build-depends: text, attoparsec, split\\n',\n", + " ' build-depends: text, attoparsec, containers, lens, mtl\\n',\n", + " ' build-depends: containers, linear, array, pqueue, mtl, lens\\n',\n", + " ' build-depends: text, attoparsec\\n',\n", + " ' build-depends: text, attoparsec, containers, linear, lens\\n',\n", + " ' build-depends: text, attoparsec, containers, linear, lens\\n',\n", + " ' build-depends: text, attoparsec, containers, pqueue, mtl, lens, split\\n',\n", + " ' build-depends: containers, linear, lens\\n',\n", + " ' build-depends: text, attoparsec, containers, linear, lens\\n',\n", + " ' build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq\\n',\n", + " ' build-depends: data-clist , lens\\n',\n", + " ' build-depends: text, attoparsec, containers, lens\\n',\n", + " ' build-depends: containers, linear, lens, mtl\\n',\n", + " ' build-depends: containers, linear, lens, mtl, multiset\\n',\n", + " ' build-depends: containers, linear, lens, mtl, multiset\\n',\n", + " ' build-depends: containers, pqueue, mtl, lens, linear, array\\n']" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "with open('../advent-of-code22.cabal') as f:\n", + " build_depends = [l for l in f.readlines() if 'build-depends' in l]\n", + "build_depends" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d0e0655a-2fad-47c9-afe1-8ae4c44949ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[', other than Main.\\n -- other-modules:\\n\\n -- LANGUAGE extensions used by modules in this package.\\n -- other-extensions:\\n build-depends: base ^>=4.16.4.0\\n hs-source-dirs: app, src\\n default-language: Haskell2010\\n\\nlibrary\\n import: common-extensions\\n build-depends: base >=4.16\\n hs-source-dirs: ., app, src\\n exposed-modules: AoC\\n\\n',\n", + " ' advent01\\n import: common-extensions, build-directives\\n main-is: advent01/Main.hs\\n build-depends: split\\n\\n',\n", + " ' advent02\\n import: common-extensions, build-directives\\n main-is: advent02/Main.hs\\n build-depends: text, attoparsec\\n\\n']" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cabal_file = open('../advent-of-code22.cabal').read()\n", + "executables = cabal_file.split('executable')[2:]\n", + "executables[:3]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "62a719db-b264-4b95-8dd0-80ab08b3622a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['split']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "e = executables[1]\n", + "e.strip().split('build-depends: ')[1].split(',')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "5f5e51ea-4457-4701-99d2-844edcec721e", + "metadata": {}, + "outputs": [], + "source": [ + "def extract(line):\n", + " parts = line.strip().split('build-depends: ')\n", + " name = parts[0].split()[0]\n", + " if len(parts) > 1:\n", + " depends = [p.strip() for p in parts[1].split('\\n')[0].split(',') if 'base' not in p]\n", + " else:\n", + " depends = []\n", + " return name, depends " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a852a10b-ee9a-46d5-a390-04f218424760", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'advent01': ['split'],\n", + " 'advent02': ['text', 'attoparsec'],\n", + " 'advent03': ['containers', 'split'],\n", + " 'advent04': ['text', 'attoparsec'],\n", + " 'advent05': ['text', 'attoparsec', 'containers'],\n", + " 'advent06': [],\n", + " 'advent07': ['text', 'attoparsec', 'containers', 'rosezipper'],\n", + " 'advent08': [],\n", + " 'advent09': ['text', 'attoparsec', 'containers', 'linear', 'lens'],\n", + " 'advent10': ['text', 'attoparsec', 'split'],\n", + " 'advent11': ['text', 'attoparsec', 'containers', 'lens', 'mtl'],\n", + " 'advent12': ['containers', 'linear', 'array', 'pqueue', 'mtl', 'lens'],\n", + " 'advent13': ['text', 'attoparsec'],\n", + " 'advent14': ['text', 'attoparsec', 'containers', 'linear', 'lens'],\n", + " 'advent15': ['text', 'attoparsec', 'containers', 'linear', 'lens'],\n", + " 'advent16': ['text',\n", + " 'attoparsec',\n", + " 'containers',\n", + " 'pqueue',\n", + " 'mtl',\n", + " 'lens',\n", + " 'split'],\n", + " 'advent17': ['containers', 'linear', 'lens'],\n", + " 'advent18': ['text', 'attoparsec', 'containers', 'linear', 'lens'],\n", + " 'advent19': ['text',\n", + " 'attoparsec',\n", + " 'containers',\n", + " 'pqueue',\n", + " 'mtl',\n", + " 'lens',\n", + " 'multiset',\n", + " 'parallel',\n", + " 'deepseq'],\n", + " 'advent20': ['data-clist', 'lens'],\n", + " 'advent21': ['text', 'attoparsec', 'containers', 'lens'],\n", + " 'advent22': ['containers', 'linear', 'lens', 'mtl'],\n", + " 'advent23': ['containers', 'linear', 'lens', 'mtl', 'multiset'],\n", + " 'advent24': ['containers', 'pqueue', 'mtl', 'lens', 'linear', 'array'],\n", + " 'advent25': []}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "modules = {e: ms for e, ms in [extract(e) for e in executables] if e.endswith(tuple(str(i) for i in range(10)))}\n", + "modules" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "57036fc2-db73-4c5b-b3bc-b7e8f9bbccda", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
arrayattoparseccontainersdata-clistdeepseqlenslinearmtlmultisetparallelpqueuerosezippersplittext
advent01FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrueFalse
advent02FalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent03FalseFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseTrueFalse
advent04FalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent05FalseTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent06FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent07FalseTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseTrueFalseTrue
advent08FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent09FalseTrueTrueFalseFalseTrueTrueFalseFalseFalseFalseFalseFalseTrue
advent10FalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrueTrue
advent11FalseTrueTrueFalseFalseTrueFalseTrueFalseFalseFalseFalseFalseTrue
advent12TrueFalseTrueFalseFalseTrueTrueTrueFalseFalseTrueFalseFalseFalse
advent13FalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent14FalseTrueTrueFalseFalseTrueTrueFalseFalseFalseFalseFalseFalseTrue
advent15FalseTrueTrueFalseFalseTrueTrueFalseFalseFalseFalseFalseFalseTrue
advent16FalseTrueTrueFalseFalseTrueFalseTrueFalseFalseTrueFalseTrueTrue
advent17FalseFalseTrueFalseFalseTrueTrueFalseFalseFalseFalseFalseFalseFalse
advent18FalseTrueTrueFalseFalseTrueTrueFalseFalseFalseFalseFalseFalseTrue
advent19FalseTrueTrueFalseTrueTrueFalseTrueTrueTrueTrueFalseFalseTrue
advent20FalseFalseFalseTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalse
advent21FalseTrueTrueFalseFalseTrueFalseFalseFalseFalseFalseFalseFalseTrue
advent22FalseFalseTrueFalseFalseTrueTrueTrueFalseFalseFalseFalseFalseFalse
advent23FalseFalseTrueFalseFalseTrueTrueTrueTrueFalseFalseFalseFalseFalse
advent24TrueFalseTrueFalseFalseTrueTrueTrueFalseFalseTrueFalseFalseFalse
advent25FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
\n", + "
" + ], + "text/plain": [ + " array attoparsec containers data-clist deepseq lens linear \\\n", + "advent01 False False False False False False False \n", + "advent02 False True False False False False False \n", + "advent03 False False True False False False False \n", + "advent04 False True False False False False False \n", + "advent05 False True True False False False False \n", + "advent06 False False False False False False False \n", + "advent07 False True True False False False False \n", + "advent08 False False False False False False False \n", + "advent09 False True True False False True True \n", + "advent10 False True False False False False False \n", + "advent11 False True True False False True False \n", + "advent12 True False True False False True True \n", + "advent13 False True False False False False False \n", + "advent14 False True True False False True True \n", + "advent15 False True True False False True True \n", + "advent16 False True True False False True False \n", + "advent17 False False True False False True True \n", + "advent18 False True True False False True True \n", + "advent19 False True True False True True False \n", + "advent20 False False False True False True False \n", + "advent21 False True True False False True False \n", + "advent22 False False True False False True True \n", + "advent23 False False True False False True True \n", + "advent24 True False True False False True True \n", + "advent25 False False False False False False False \n", + "\n", + " mtl multiset parallel pqueue rosezipper split text \n", + "advent01 False False False False False True False \n", + "advent02 False False False False False False True \n", + "advent03 False False False False False True False \n", + "advent04 False False False False False False True \n", + "advent05 False False False False False False True \n", + "advent06 False False False False False False False \n", + "advent07 False False False False True False True \n", + "advent08 False False False False False False False \n", + "advent09 False False False False False False True \n", + "advent10 False False False False False True True \n", + "advent11 True False False False False False True \n", + "advent12 True False False True False False False \n", + "advent13 False False False False False False True \n", + "advent14 False False False False False False True \n", + "advent15 False False False False False False True \n", + "advent16 True False False True False True True \n", + "advent17 False False False False False False False \n", + "advent18 False False False False False False True \n", + "advent19 True True True True False False True \n", + "advent20 False False False False False False False \n", + "advent21 False False False False False False True \n", + "advent22 True False False False False False False \n", + "advent23 True True False False False False False \n", + "advent24 True False False True False False False \n", + "advent25 False False False False False False False " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "all_modules = set(m for p in modules for m in modules[p])\n", + "modules_df = pd.DataFrame.from_dict({p: {m: m in modules[p] for m in sorted(all_modules)} for p in modules}, orient='index').sort_index()\n", + "modules_df" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2eec3a74-e533-4d59-b495-9e774ca470e5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "| | 0 |\n", + "|:-----------|----:|\n", + "| containers | 16 |\n", + "| attoparsec | 14 |\n", + "| lens | 14 |\n", + "| text | 14 |\n", + "| linear | 9 |\n", + "| mtl | 7 |\n", + "| pqueue | 4 |\n", + "| split | 4 |\n", + "| array | 2 |\n", + "| multiset | 2 |\n", + "| data-clist | 1 |\n", + "| deepseq | 1 |\n", + "| parallel | 1 |\n", + "| rosezipper | 1 |\n" + ] + } + ], + "source": [ + "print(modules_df.sum().sort_values(ascending=False).to_markdown())" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "d5c8f2ac-1575-49c4-b2c1-458419b9afd8", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array(['containers', 'attoparsec', 'lens', 'text', 'linear', 'mtl',\n", + " 'pqueue', 'split', 'array', 'multiset', 'data-clist', 'deepseq',\n", + " 'parallel', 'rosezipper'], dtype=object)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted_modules = modules_df.sum().sort_values(ascending=False).index.values\n", + "sorted_modules" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "1802f0e4-c0b4-4c07-9b9b-a90d01e656d2", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
containersattoparseclenstextlinearmtlpqueuesplitarraymultisetdata-clistdeepseqparallelrosezipper
advent01FalseFalseFalseFalseFalseFalseFalseTrueFalseFalseFalseFalseFalseFalse
advent02FalseTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent03TrueFalseFalseFalseFalseFalseFalseTrueFalseFalseFalseFalseFalseFalse
advent04FalseTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent05TrueTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent06FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent07TrueTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent08FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent09TrueTrueTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent10FalseTrueFalseTrueFalseFalseFalseTrueFalseFalseFalseFalseFalseFalse
advent11TrueTrueTrueTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalse
advent12TrueFalseTrueFalseTrueTrueTrueFalseTrueFalseFalseFalseFalseFalse
advent13FalseTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent14TrueTrueTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent15TrueTrueTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent16TrueTrueTrueTrueFalseTrueTrueTrueFalseFalseFalseFalseFalseFalse
advent17TrueFalseTrueFalseTrueFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent18TrueTrueTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent19TrueTrueTrueTrueFalseTrueTrueFalseFalseTrueFalseTrueTrueFalse
advent20FalseFalseTrueFalseFalseFalseFalseFalseFalseFalseTrueFalseFalseFalse
advent21TrueTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent22TrueFalseTrueFalseTrueTrueFalseFalseFalseFalseFalseFalseFalseFalse
advent23TrueFalseTrueFalseTrueTrueFalseFalseFalseTrueFalseFalseFalseFalse
advent24TrueFalseTrueFalseTrueTrueTrueFalseTrueFalseFalseFalseFalseFalse
advent25FalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
\n", + "
" + ], + "text/plain": [ + " containers attoparsec lens text linear mtl pqueue split \\\n", + "advent01 False False False False False False False True \n", + "advent02 False True False True False False False False \n", + "advent03 True False False False False False False True \n", + "advent04 False True False True False False False False \n", + "advent05 True True False True False False False False \n", + "advent06 False False False False False False False False \n", + "advent07 True True False True False False False False \n", + "advent08 False False False False False False False False \n", + "advent09 True True True True True False False False \n", + "advent10 False True False True False False False True \n", + "advent11 True True True True False True False False \n", + "advent12 True False True False True True True False \n", + "advent13 False True False True False False False False \n", + "advent14 True True True True True False False False \n", + "advent15 True True True True True False False False \n", + "advent16 True True True True False True True True \n", + "advent17 True False True False True False False False \n", + "advent18 True True True True True False False False \n", + "advent19 True True True True False True True False \n", + "advent20 False False True False False False False False \n", + "advent21 True True True True False False False False \n", + "advent22 True False True False True True False False \n", + "advent23 True False True False True True False False \n", + "advent24 True False True False True True True False \n", + "advent25 False False False False False False False False \n", + "\n", + " array multiset data-clist deepseq parallel rosezipper \n", + "advent01 False False False False False False \n", + "advent02 False False False False False False \n", + "advent03 False False False False False False \n", + "advent04 False False False False False False \n", + "advent05 False False False False False False \n", + "advent06 False False False False False False \n", + "advent07 False False False False False True \n", + "advent08 False False False False False False \n", + "advent09 False False False False False False \n", + "advent10 False False False False False False \n", + "advent11 False False False False False False \n", + "advent12 True False False False False False \n", + "advent13 False False False False False False \n", + "advent14 False False False False False False \n", + "advent15 False False False False False False \n", + "advent16 False False False False False False \n", + "advent17 False False False False False False \n", + "advent18 False False False False False False \n", + "advent19 False True False True True False \n", + "advent20 False False True False False False \n", + "advent21 False False False False False False \n", + "advent22 False False False False False False \n", + "advent23 False True False False False False \n", + "advent24 True False False False False False \n", + "advent25 False False False False False False " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "modules_sorted_cols = modules_df[sorted_modules]\n", + "modules_sorted_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "da22ede4-ac7c-4d32-9396-4cf585f97ba7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
programmodulepresent
12advent01splitTrue
15advent02attoparsecTrue
27advent02textTrue
30advent03containersTrue
40advent03splitTrue
............
324advent24containersTrue
327advent24lensTrue
328advent24linearTrue
329advent24mtlTrue
332advent24pqueueTrue
\n", + "

90 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " program module present\n", + "12 advent01 split True\n", + "15 advent02 attoparsec True\n", + "27 advent02 text True\n", + "30 advent03 containers True\n", + "40 advent03 split True\n", + ".. ... ... ...\n", + "324 advent24 containers True\n", + "327 advent24 lens True\n", + "328 advent24 linear True\n", + "329 advent24 mtl True\n", + "332 advent24 pqueue True\n", + "\n", + "[90 rows x 3 columns]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "modules_scatter = modules_df.stack().reset_index()\n", + "modules_scatter.columns = ['program', 'module', 'present']\n", + "modules_scatter = modules_scatter[modules_scatter.present]\n", + "modules_scatter" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "fa6a99a2-749a-48d5-9009-11a45eb2722a", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "modules_scatter.plot.scatter(x='program', y='module', s=80, rot=45, figsize=(10, 6))" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "0e1cb390-cfce-41aa-b18f-b3d9fee57ae0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.colors.ListedColormap(['white', 'blue'])\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", + "ax.imshow(modules_df.to_numpy().T, cmap=cmap)\n", + "plt.xticks(range(modules_df.index.size), labels=modules_df.index.values, rotation=90);\n", + "plt.yticks(range(modules_df.columns.size), labels=modules_df.columns.values);\n", + "\n", + "ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5);\n", + "plt.savefig('packages.png');" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "6436d177-2695-4847-b00c-bf7f4a38f1fe", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.colors.ListedColormap(['white', 'blue'])\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", + "ax.imshow(modules_sorted_cols.to_numpy().T, cmap=cmap)\n", + "plt.xticks(range(modules_sorted_cols.index.size), labels=modules_sorted_cols.index.values, rotation=90);\n", + "plt.yticks(range(modules_sorted_cols.columns.size), labels=modules_sorted_cols.columns.values);\n", + "\n", + "ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5);\n", + "plt.savefig('packages_sorted.png');" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "d79246cc-4471-43ac-ba76-d720acbb7435", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['../advent01/Main.hs',\n", + " '../advent02/Main.hs',\n", + " '../advent03/Main.hs',\n", + " '../advent04/Main.hs',\n", + " '../advent05/Main.hs',\n", + " '../advent06/Main.hs',\n", + " '../advent07/Main.hs',\n", + " '../advent08/Main.hs',\n", + " '../advent09/Main.hs',\n", + " '../advent10/Main.hs',\n", + " '../advent11/Main.hs',\n", + " '../advent12/Main.hs',\n", + " '../advent13/Main.hs',\n", + " '../advent14/Main.hs',\n", + " '../advent15/Main.hs',\n", + " '../advent16/Main.hs',\n", + " '../advent17/Main.hs',\n", + " '../advent18/Main.hs',\n", + " '../advent19/Main.hs',\n", + " '../advent20/Main.hs',\n", + " '../advent21/Main.hs',\n", + " '../advent22/Main.hs',\n", + " '../advent23/Main.hs',\n", + " '../advent24/Main.hs',\n", + " '../advent25/Main.hs']" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mains = list(sorted(f for f in glob.glob('../advent*/Main.hs')))\n", + "mains" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "f9076c9f-fc86-435b-9471-99726bfbfb87", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'advent01': [('AoC', False),\n", + " ('Data.List', False),\n", + " ('Data.List.Split', False),\n", + " ('Data.Ord', False)],\n", + " 'advent02': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False)],\n", + " 'advent03': [('AoC', False),\n", + " ('Data.Char', False),\n", + " ('Data.Set', True),\n", + " ('Data.List', False),\n", + " ('Data.List.Split', False)],\n", + " 'advent04': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False)],\n", + " 'advent05': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.List', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.IntMap.Strict', True),\n", + " ('Data.IntMap.Strict', False)],\n", + " 'advent06': [('AoC', False), ('Data.List', False)],\n", + " 'advent07': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.Char', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.Tree', False),\n", + " ('Data.Tree.Zipper', False),\n", + " ('Data.Map.Strict', True),\n", + " ('Data.List', False)],\n", + " 'advent08': [('AoC', False), ('Data.List', False)],\n", + " 'advent09': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.List', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False),\n", + " ('Control.Lens', False)],\n", + " 'advent10': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.List', False),\n", + " ('Data.List.Split', False)],\n", + " 'advent11': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.List', False),\n", + " ('Data.IntMap.Strict', True),\n", + " ('Data.IntMap', False),\n", + " ('Control.Lens', False),\n", + " ('Control.Monad.State.Strict', False),\n", + " ('Control.Monad.Reader', False),\n", + " ('Control.Monad.Writer', False),\n", + " ('Control.Monad.RWS.Strict', False)],\n", + " 'advent12': [('AoC', False),\n", + " ('Data.PQueue.Prio.Min', True),\n", + " ('Data.Set', True),\n", + " ('Data.Sequence', True),\n", + " ('Data.Sequence', False),\n", + " ('Data.Foldable', False),\n", + " ('Data.Char', False),\n", + " ('Control.Monad.Reader', False),\n", + " ('Control.Lens', False),\n", + " ('Linear', False),\n", + " ('Data.Array.IArray', False)],\n", + " 'advent13': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.List', False)],\n", + " 'advent14': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Data.List', False),\n", + " ('Data.Ix', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False),\n", + " ('Control.Lens', False)],\n", + " 'advent15': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Data.Ix', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False)],\n", + " 'advent16': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.PQueue.Prio.Max', True),\n", + " ('Data.Set', True),\n", + " ('Data.Sequence', True),\n", + " ('Data.Map.Strict', True),\n", + " ('Data.Map.Strict', False),\n", + " ('Data.Sequence', False),\n", + " ('Data.List', False),\n", + " ('Data.List.Split', False),\n", + " ('Data.Ord', False),\n", + " ('Control.Monad.Reader', False),\n", + " ('Control.Lens', False)],\n", + " 'advent17': [('AoC', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False),\n", + " ('Control.Lens', False),\n", + " ('Data.Maybe', False)],\n", + " 'advent18': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False),\n", + " ('Control.Lens', False),\n", + " ('Data.Ix', False),\n", + " ('Data.Maybe', False)],\n", + " 'advent19': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.PQueue.Prio.Max', True),\n", + " ('Data.Set', True),\n", + " ('Data.Sequence', True),\n", + " ('Data.Map.Strict', True),\n", + " ('Data.Map.Strict', False),\n", + " ('Data.MultiSet', False),\n", + " ('Data.Sequence', False),\n", + " ('Data.List', False),\n", + " ('Data.Maybe', False),\n", + " ('Control.Monad.Reader', False),\n", + " ('Control.Lens', False),\n", + " ('GHC.Generics', False),\n", + " ('Control.Parallel.Strategies', False),\n", + " ('Control.DeepSeq', False)],\n", + " 'advent20': [('AoC', False),\n", + " ('Data.List', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.CircularList', False),\n", + " ('Control.Lens', False)],\n", + " 'advent21': [('AoC', False),\n", + " ('Data.Text', False),\n", + " ('Data.Text.IO', True),\n", + " ('Data.Attoparsec.Text', False),\n", + " ('Control.Applicative', False),\n", + " ('Data.Map.Strict', True),\n", + " ('Data.Map.Strict', False),\n", + " ('Control.Lens', False)],\n", + " 'advent22': [('AoC', False),\n", + " ('Prelude', False),\n", + " ('Data.Map.Strict', True),\n", + " ('Data.Map.Strict', False),\n", + " ('Linear', False),\n", + " ('Control.Lens', False),\n", + " ('Data.Ix', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.Char', False),\n", + " ('Control.Monad.Reader', False)],\n", + " 'advent23': [('AoC', False),\n", + " ('Data.Set', True),\n", + " ('Linear', False),\n", + " ('Control.Lens', False),\n", + " ('Data.Ix', False),\n", + " ('Data.Maybe', False),\n", + " ('Data.Monoid', False),\n", + " ('Data.MultiSet', False),\n", + " ('Control.Monad.State.Strict', False)],\n", + " 'advent24': [('AoC', False),\n", + " ('Data.PQueue.Prio.Min', True),\n", + " ('Data.Set', True),\n", + " ('Data.IntMap.Strict', True),\n", + " ('Data.Sequence', True),\n", + " ('Data.Sequence', False),\n", + " ('Control.Monad.Reader', False),\n", + " ('Control.Lens', False),\n", + " ('Linear', False),\n", + " ('Data.Array.IArray', False),\n", + " ('Data.List', False),\n", + " ('Data.Maybe', False)],\n", + " 'advent25': [('AoC', False), ('Data.List', False)]}" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "main_imports = {}\n", + "\n", + "for m in mains:\n", + " with open(m) as f:\n", + " lines = f.readlines()\n", + " import_lines = [l for l in lines if l.strip().startswith('import') if 'Debug.Trace' not in l]\n", + " imports = []\n", + " for i in import_lines:\n", + " words = i.strip().split()\n", + " if 'qualified' in i:\n", + " imports.append((words[2], True))\n", + " else:\n", + " imports.append((words[1], False))\n", + " main_imports[m.split('/')[1]] = imports\n", + "\n", + "main_imports" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "3260db91-68df-47d3-b4c3-8745ea974033", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(('AoC', False), 25),\n", + " (('Data.List', False), 16),\n", + " (('Data.Text', False), 14),\n", + " (('Data.Text.IO', True), 14),\n", + " (('Data.Attoparsec.Text', False), 14),\n", + " (('Control.Lens', False), 13),\n", + " (('Data.Set', True), 11),\n", + " (('Control.Applicative', False), 10),\n", + " (('Data.Maybe', False), 10),\n", + " (('Linear', False), 9),\n", + " (('Control.Monad.Reader', False), 6),\n", + " (('Data.Map.Strict', True), 5),\n", + " (('Data.Ix', False), 5),\n", + " (('Data.List.Split', False), 4),\n", + " (('Data.Char', False), 4),\n", + " (('Data.Sequence', True), 4),\n", + " (('Data.Sequence', False), 4),\n", + " (('Data.Map.Strict', False), 4),\n", + " (('Data.IntMap.Strict', True), 3),\n", + " (('Data.Ord', False), 2),\n", + " (('Control.Monad.State.Strict', False), 2),\n", + " (('Data.PQueue.Prio.Min', True), 2),\n", + " (('Data.Array.IArray', False), 2),\n", + " (('Data.PQueue.Prio.Max', True), 2),\n", + " (('Data.MultiSet', False), 2),\n", + " (('Data.IntMap.Strict', False), 1),\n", + " (('Data.Tree', False), 1),\n", + " (('Data.Tree.Zipper', False), 1),\n", + " (('Data.IntMap', False), 1),\n", + " (('Control.Monad.Writer', False), 1),\n", + " (('Control.Monad.RWS.Strict', False), 1),\n", + " (('Data.Foldable', False), 1),\n", + " (('GHC.Generics', False), 1),\n", + " (('Control.Parallel.Strategies', False), 1),\n", + " (('Control.DeepSeq', False), 1),\n", + " (('Data.CircularList', False), 1),\n", + " (('Prelude', False), 1),\n", + " (('Data.Monoid', False), 1)]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import_counts = collections.Counter(l for ls in main_imports.values() for l in ls)\n", + "import_counts.most_common()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "3f683faa-4d1d-4269-a66e-0ea848804e03", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'advent01': {'AoC', 'Data.List', 'Data.List.Split', 'Data.Ord'},\n", + " 'advent02': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent03': {'AoC', 'Data.Char', 'Data.List', 'Data.List.Split', 'Data.Set'},\n", + " 'advent04': {'AoC', 'Data.Attoparsec.Text', 'Data.Text', 'Data.Text.IO'},\n", + " 'advent05': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.IntMap.Strict',\n", + " 'Data.List',\n", + " 'Data.Maybe',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent06': {'AoC', 'Data.List'},\n", + " 'advent07': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Char',\n", + " 'Data.List',\n", + " 'Data.Map.Strict',\n", + " 'Data.Maybe',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'Data.Tree',\n", + " 'Data.Tree.Zipper'},\n", + " 'advent08': {'AoC', 'Data.List'},\n", + " 'advent09': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Control.Lens',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.List',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'Linear'},\n", + " 'advent10': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.List',\n", + " 'Data.List.Split',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent11': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Control.Lens',\n", + " 'Control.Monad.RWS.Strict',\n", + " 'Control.Monad.Reader',\n", + " 'Control.Monad.State.Strict',\n", + " 'Control.Monad.Writer',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.IntMap',\n", + " 'Data.IntMap.Strict',\n", + " 'Data.List',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent12': {'AoC',\n", + " 'Control.Lens',\n", + " 'Control.Monad.Reader',\n", + " 'Data.Array.IArray',\n", + " 'Data.Char',\n", + " 'Data.Foldable',\n", + " 'Data.PQueue.Prio.Min',\n", + " 'Data.Sequence',\n", + " 'Data.Set',\n", + " 'Linear'},\n", + " 'advent13': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.List',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent14': {'AoC',\n", + " 'Control.Lens',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Ix',\n", + " 'Data.List',\n", + " 'Data.Maybe',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'Linear'},\n", + " 'advent15': {'AoC',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Ix',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'Linear'},\n", + " 'advent16': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Control.Lens',\n", + " 'Control.Monad.Reader',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.List',\n", + " 'Data.List.Split',\n", + " 'Data.Map.Strict',\n", + " 'Data.Ord',\n", + " 'Data.PQueue.Prio.Max',\n", + " 'Data.Sequence',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent17': {'AoC', 'Control.Lens', 'Data.Maybe', 'Data.Set', 'Linear'},\n", + " 'advent18': {'AoC',\n", + " 'Control.Lens',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Ix',\n", + " 'Data.Maybe',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'Linear'},\n", + " 'advent19': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Control.DeepSeq',\n", + " 'Control.Lens',\n", + " 'Control.Monad.Reader',\n", + " 'Control.Parallel.Strategies',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.List',\n", + " 'Data.Map.Strict',\n", + " 'Data.Maybe',\n", + " 'Data.MultiSet',\n", + " 'Data.PQueue.Prio.Max',\n", + " 'Data.Sequence',\n", + " 'Data.Set',\n", + " 'Data.Text',\n", + " 'Data.Text.IO',\n", + " 'GHC.Generics'},\n", + " 'advent20': {'AoC',\n", + " 'Control.Lens',\n", + " 'Data.CircularList',\n", + " 'Data.List',\n", + " 'Data.Maybe'},\n", + " 'advent21': {'AoC',\n", + " 'Control.Applicative',\n", + " 'Control.Lens',\n", + " 'Data.Attoparsec.Text',\n", + " 'Data.Map.Strict',\n", + " 'Data.Text',\n", + " 'Data.Text.IO'},\n", + " 'advent22': {'AoC',\n", + " 'Control.Lens',\n", + " 'Control.Monad.Reader',\n", + " 'Data.Char',\n", + " 'Data.Ix',\n", + " 'Data.Map.Strict',\n", + " 'Data.Maybe',\n", + " 'Linear',\n", + " 'Prelude'},\n", + " 'advent23': {'AoC',\n", + " 'Control.Lens',\n", + " 'Control.Monad.State.Strict',\n", + " 'Data.Ix',\n", + " 'Data.Maybe',\n", + " 'Data.Monoid',\n", + " 'Data.MultiSet',\n", + " 'Data.Set',\n", + " 'Linear'},\n", + " 'advent24': {'AoC',\n", + " 'Control.Lens',\n", + " 'Control.Monad.Reader',\n", + " 'Data.Array.IArray',\n", + " 'Data.IntMap.Strict',\n", + " 'Data.List',\n", + " 'Data.Maybe',\n", + " 'Data.PQueue.Prio.Min',\n", + " 'Data.Sequence',\n", + " 'Data.Set',\n", + " 'Linear'},\n", + " 'advent25': {'AoC', 'Data.List'}}" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "main_imports_unqualified = {m: set(i[0] for i in main_imports[m]) for m in main_imports}\n", + "main_imports_unqualified" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "e5ff5780-e511-41ab-9207-0cc6bdaecb64", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('AoC', 25),\n", + " ('Data.List', 16),\n", + " ('Data.Text', 14),\n", + " ('Data.Attoparsec.Text', 14),\n", + " ('Data.Text.IO', 14),\n", + " ('Control.Lens', 13),\n", + " ('Data.Set', 11),\n", + " ('Control.Applicative', 10),\n", + " ('Data.Maybe', 10),\n", + " ('Linear', 9),\n", + " ('Control.Monad.Reader', 6),\n", + " ('Data.Map.Strict', 5),\n", + " ('Data.Ix', 5),\n", + " ('Data.List.Split', 4),\n", + " ('Data.Char', 4),\n", + " ('Data.Sequence', 4),\n", + " ('Data.IntMap.Strict', 3),\n", + " ('Data.Ord', 2),\n", + " ('Control.Monad.State.Strict', 2),\n", + " ('Data.PQueue.Prio.Min', 2),\n", + " ('Data.Array.IArray', 2),\n", + " ('Data.PQueue.Prio.Max', 2),\n", + " ('Data.MultiSet', 2),\n", + " ('Data.Tree', 1),\n", + " ('Data.Tree.Zipper', 1),\n", + " ('Control.Monad.Writer', 1),\n", + " ('Control.Monad.RWS.Strict', 1),\n", + " ('Data.IntMap', 1),\n", + " ('Data.Foldable', 1),\n", + " ('Control.DeepSeq', 1),\n", + " ('GHC.Generics', 1),\n", + " ('Control.Parallel.Strategies', 1),\n", + " ('Data.CircularList', 1),\n", + " ('Prelude', 1),\n", + " ('Data.Monoid', 1)]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import_counts_unqualified = collections.Counter(l for ls in main_imports_unqualified.values() for l in ls)\n", + "import_counts_unqualified.most_common()" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "e0580f26-9f6d-49f9-83ff-92dbd190aad6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AoCControl.ApplicativeControl.DeepSeqControl.LensControl.Monad.RWS.StrictControl.Monad.ReaderControl.Monad.State.StrictControl.Monad.WriterControl.Parallel.StrategiesData.Array.IArray...Data.PQueue.Prio.MinData.SequenceData.SetData.TextData.Text.IOData.TreeData.Tree.ZipperGHC.GenericsLinearPrelude
advent01TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent02TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent03TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseTrueFalseFalseFalseFalseFalseFalseFalse
advent04TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent05TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent06TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent07TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueTrueTrueFalseFalseFalse
advent08TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent09TrueTrueFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseTrueTrueTrueFalseFalseFalseTrueFalse
advent10TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent11TrueTrueFalseTrueTrueTrueTrueTrueFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent12TrueFalseFalseTrueFalseTrueFalseFalseFalseTrue...TrueTrueTrueFalseFalseFalseFalseFalseTrueFalse
advent13TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent14TrueFalseFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseTrueTrueTrueFalseFalseFalseTrueFalse
advent15TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseTrueTrueTrueFalseFalseFalseTrueFalse
advent16TrueTrueFalseTrueFalseTrueFalseFalseFalseFalse...FalseTrueTrueTrueTrueFalseFalseFalseFalseFalse
advent17TrueFalseFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseTrueFalseFalseFalseFalseFalseTrueFalse
advent18TrueFalseFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseTrueTrueTrueFalseFalseFalseTrueFalse
advent19TrueTrueTrueTrueFalseTrueFalseFalseTrueFalse...FalseTrueTrueTrueTrueFalseFalseTrueFalseFalse
advent20TrueFalseFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent21TrueTrueFalseTrueFalseFalseFalseFalseFalseFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
advent22TrueFalseFalseTrueFalseTrueFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseTrueTrue
advent23TrueFalseFalseTrueFalseFalseTrueFalseFalseFalse...FalseFalseTrueFalseFalseFalseFalseFalseTrueFalse
advent24TrueFalseFalseTrueFalseTrueFalseFalseFalseTrue...TrueTrueTrueFalseFalseFalseFalseFalseTrueFalse
advent25TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
\n", + "

25 rows × 35 columns

\n", + "
" + ], + "text/plain": [ + " AoC Control.Applicative Control.DeepSeq Control.Lens \\\n", + "advent01 True False False False \n", + "advent02 True True False False \n", + "advent03 True False False False \n", + "advent04 True False False False \n", + "advent05 True True False False \n", + "advent06 True False False False \n", + "advent07 True True False False \n", + "advent08 True False False False \n", + "advent09 True True False True \n", + "advent10 True True False False \n", + "advent11 True True False True \n", + "advent12 True False False True \n", + "advent13 True True False False \n", + "advent14 True False False True \n", + "advent15 True False False False \n", + "advent16 True True False True \n", + "advent17 True False False True \n", + "advent18 True False False True \n", + "advent19 True True True True \n", + "advent20 True False False True \n", + "advent21 True True False True \n", + "advent22 True False False True \n", + "advent23 True False False True \n", + "advent24 True False False True \n", + "advent25 True False False False \n", + "\n", + " Control.Monad.RWS.Strict Control.Monad.Reader \\\n", + "advent01 False False \n", + "advent02 False False \n", + "advent03 False False \n", + "advent04 False False \n", + "advent05 False False \n", + "advent06 False False \n", + "advent07 False False \n", + "advent08 False False \n", + "advent09 False False \n", + "advent10 False False \n", + "advent11 True True \n", + "advent12 False True \n", + "advent13 False False \n", + "advent14 False False \n", + "advent15 False False \n", + "advent16 False True \n", + "advent17 False False \n", + "advent18 False False \n", + "advent19 False True \n", + "advent20 False False \n", + "advent21 False False \n", + "advent22 False True \n", + "advent23 False False \n", + "advent24 False True \n", + "advent25 False False \n", + "\n", + " Control.Monad.State.Strict Control.Monad.Writer \\\n", + "advent01 False False \n", + "advent02 False False \n", + "advent03 False False \n", + "advent04 False False \n", + "advent05 False False \n", + "advent06 False False \n", + "advent07 False False \n", + "advent08 False False \n", + "advent09 False False \n", + "advent10 False False \n", + "advent11 True True \n", + "advent12 False False \n", + "advent13 False False \n", + "advent14 False False \n", + "advent15 False False \n", + "advent16 False False \n", + "advent17 False False \n", + "advent18 False False \n", + "advent19 False False \n", + "advent20 False False \n", + "advent21 False False \n", + "advent22 False False \n", + "advent23 True False \n", + "advent24 False False \n", + "advent25 False False \n", + "\n", + " Control.Parallel.Strategies Data.Array.IArray ... \\\n", + "advent01 False False ... \n", + "advent02 False False ... \n", + "advent03 False False ... \n", + "advent04 False False ... \n", + "advent05 False False ... \n", + "advent06 False False ... \n", + "advent07 False False ... \n", + "advent08 False False ... \n", + "advent09 False False ... \n", + "advent10 False False ... \n", + "advent11 False False ... \n", + "advent12 False True ... \n", + "advent13 False False ... \n", + "advent14 False False ... \n", + "advent15 False False ... \n", + "advent16 False False ... \n", + "advent17 False False ... \n", + "advent18 False False ... \n", + "advent19 True False ... \n", + "advent20 False False ... \n", + "advent21 False False ... \n", + "advent22 False False ... \n", + "advent23 False False ... \n", + "advent24 False True ... \n", + "advent25 False False ... \n", + "\n", + " Data.PQueue.Prio.Min Data.Sequence Data.Set Data.Text \\\n", + "advent01 False False False False \n", + "advent02 False False False True \n", + "advent03 False False True False \n", + "advent04 False False False True \n", + "advent05 False False False True \n", + "advent06 False False False False \n", + "advent07 False False False True \n", + "advent08 False False False False \n", + "advent09 False False True True \n", + "advent10 False False False True \n", + "advent11 False False False True \n", + "advent12 True True True False \n", + "advent13 False False False True \n", + "advent14 False False True True \n", + "advent15 False False True True \n", + "advent16 False True True True \n", + "advent17 False False True False \n", + "advent18 False False True True \n", + "advent19 False True True True \n", + "advent20 False False False False \n", + "advent21 False False False True \n", + "advent22 False False False False \n", + "advent23 False False True False \n", + "advent24 True True True False \n", + "advent25 False False False False \n", + "\n", + " Data.Text.IO Data.Tree Data.Tree.Zipper GHC.Generics Linear \\\n", + "advent01 False False False False False \n", + "advent02 True False False False False \n", + "advent03 False False False False False \n", + "advent04 True False False False False \n", + "advent05 True False False False False \n", + "advent06 False False False False False \n", + "advent07 True True True False False \n", + "advent08 False False False False False \n", + "advent09 True False False False True \n", + "advent10 True False False False False \n", + "advent11 True False False False False \n", + "advent12 False False False False True \n", + "advent13 True False False False False \n", + "advent14 True False False False True \n", + "advent15 True False False False True \n", + "advent16 True False False False False \n", + "advent17 False False False False True \n", + "advent18 True False False False True \n", + "advent19 True False False True False \n", + "advent20 False False False False False \n", + "advent21 True False False False False \n", + "advent22 False False False False True \n", + "advent23 False False False False True \n", + "advent24 False False False False True \n", + "advent25 False False False False False \n", + "\n", + " Prelude \n", + "advent01 False \n", + "advent02 False \n", + "advent03 False \n", + "advent04 False \n", + "advent05 False \n", + "advent06 False \n", + "advent07 False \n", + "advent08 False \n", + "advent09 False \n", + "advent10 False \n", + "advent11 False \n", + "advent12 False \n", + "advent13 False \n", + "advent14 False \n", + "advent15 False \n", + "advent16 False \n", + "advent17 False \n", + "advent18 False \n", + "advent19 False \n", + "advent20 False \n", + "advent21 False \n", + "advent22 True \n", + "advent23 False \n", + "advent24 False \n", + "advent25 False \n", + "\n", + "[25 rows x 35 columns]" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "all_imports = set(m for p in main_imports_unqualified for m in main_imports_unqualified[p])\n", + "imports_df = pd.DataFrame.from_dict(\n", + " {p: {m: m in main_imports_unqualified[p] \n", + " for m in sorted(all_imports)} \n", + " for p in main_imports_unqualified}, \n", + " orient='index').sort_index()\n", + "imports_df" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "3668bdab-5b8f-4ab0-b788-002f0ced7b8c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "| | 0 |\n", + "|:----------------------------|----:|\n", + "| AoC | 25 |\n", + "| Data.List | 16 |\n", + "| Data.Text | 14 |\n", + "| Data.Attoparsec.Text | 14 |\n", + "| Data.Text.IO | 14 |\n", + "| Control.Lens | 13 |\n", + "| Data.Set | 11 |\n", + "| Data.Maybe | 10 |\n", + "| Control.Applicative | 10 |\n", + "| Linear | 9 |\n", + "| Control.Monad.Reader | 6 |\n", + "| Data.Map.Strict | 5 |\n", + "| Data.Ix | 5 |\n", + "| Data.Sequence | 4 |\n", + "| Data.List.Split | 4 |\n", + "| Data.Char | 4 |\n", + "| Data.IntMap.Strict | 3 |\n", + "| Data.Array.IArray | 2 |\n", + "| Control.Monad.State.Strict | 2 |\n", + "| Data.MultiSet | 2 |\n", + "| Data.Ord | 2 |\n", + "| Data.PQueue.Prio.Max | 2 |\n", + "| Data.PQueue.Prio.Min | 2 |\n", + "| Data.Tree | 1 |\n", + "| Data.Tree.Zipper | 1 |\n", + "| GHC.Generics | 1 |\n", + "| Control.DeepSeq | 1 |\n", + "| Data.Monoid | 1 |\n", + "| Data.IntMap | 1 |\n", + "| Data.Foldable | 1 |\n", + "| Data.CircularList | 1 |\n", + "| Control.Parallel.Strategies | 1 |\n", + "| Control.Monad.Writer | 1 |\n", + "| Control.Monad.RWS.Strict | 1 |\n", + "| Prelude | 1 |\n" + ] + } + ], + "source": [ + "print(imports_df.sum().sort_values(ascending=False).to_markdown())" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "3f3e9d52-87b4-4a2d-889d-0bd925f967b0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
programmodulepresent
0advent01AoCTrue
17advent01Data.ListTrue
18advent01Data.List.SplitTrue
23advent01Data.OrdTrue
35advent02AoCTrue
............
831advent24Data.SequenceTrue
832advent24Data.SetTrue
838advent24LinearTrue
840advent25AoCTrue
857advent25Data.ListTrue
\n", + "

191 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " program module present\n", + "0 advent01 AoC True\n", + "17 advent01 Data.List True\n", + "18 advent01 Data.List.Split True\n", + "23 advent01 Data.Ord True\n", + "35 advent02 AoC True\n", + ".. ... ... ...\n", + "831 advent24 Data.Sequence True\n", + "832 advent24 Data.Set True\n", + "838 advent24 Linear True\n", + "840 advent25 AoC True\n", + "857 advent25 Data.List True\n", + "\n", + "[191 rows x 3 columns]" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "imports_scatter = imports_df.stack().reset_index()\n", + "imports_scatter.columns = ['program', 'module', 'present']\n", + "imports_scatter = imports_scatter[imports_scatter.present]\n", + "imports_scatter" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "1b22b8c9-a14f-406d-bd77-ba7d7b3c3ffa", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "imports_scatter.plot.scatter(x='program', y='module', s=80, rot=45, figsize=(10, 10))" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "9552d5f9-cc44-4d49-b97e-8961556878c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "35" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "imports_df.columns.size" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "fa42c909-7c89-4351-97fd-150138892255", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array(['AoC', 'Data.List', 'Data.Text', 'Data.Attoparsec.Text',\n", + " 'Data.Text.IO', 'Control.Lens', 'Data.Set', 'Data.Maybe',\n", + " 'Control.Applicative', 'Linear', 'Control.Monad.Reader',\n", + " 'Data.Map.Strict', 'Data.Ix', 'Data.Sequence', 'Data.List.Split',\n", + " 'Data.Char', 'Data.IntMap.Strict', 'Data.Array.IArray',\n", + " 'Control.Monad.State.Strict', 'Data.MultiSet', 'Data.Ord',\n", + " 'Data.PQueue.Prio.Max', 'Data.PQueue.Prio.Min', 'Data.Tree',\n", + " 'Data.Tree.Zipper', 'GHC.Generics', 'Control.DeepSeq',\n", + " 'Data.Monoid', 'Data.IntMap', 'Data.Foldable', 'Data.CircularList',\n", + " 'Control.Parallel.Strategies', 'Control.Monad.Writer',\n", + " 'Control.Monad.RWS.Strict', 'Prelude'], dtype=object)" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted_imports = imports_df.sum().sort_values(ascending=False).index.values\n", + "sorted_imports" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "8d845f2f-4b8f-49cf-92a8-342fd368c71f", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AoCData.ListData.TextData.Attoparsec.TextData.Text.IOControl.LensData.SetData.MaybeControl.ApplicativeLinear...GHC.GenericsControl.DeepSeqData.MonoidData.IntMapData.FoldableData.CircularListControl.Parallel.StrategiesControl.Monad.WriterControl.Monad.RWS.StrictPrelude
advent01TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent02TrueFalseTrueTrueTrueFalseFalseFalseTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent03TrueTrueFalseFalseFalseFalseTrueFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent04TrueFalseTrueTrueTrueFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent05TrueTrueTrueTrueTrueFalseFalseTrueTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent06TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent07TrueTrueTrueTrueTrueFalseFalseTrueTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent08TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent09TrueTrueTrueTrueTrueTrueTrueFalseTrueTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent10TrueTrueTrueTrueTrueFalseFalseFalseTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent11TrueTrueTrueTrueTrueTrueFalseFalseTrueFalse...FalseFalseFalseTrueFalseFalseFalseTrueTrueFalse
advent12TrueFalseFalseFalseFalseTrueTrueFalseFalseTrue...FalseFalseFalseFalseTrueFalseFalseFalseFalseFalse
advent13TrueTrueTrueTrueTrueFalseFalseFalseTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent14TrueTrueTrueTrueTrueTrueTrueTrueFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent15TrueFalseTrueTrueTrueFalseTrueFalseFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent16TrueTrueTrueTrueTrueTrueTrueFalseTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent17TrueFalseFalseFalseFalseTrueTrueTrueFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent18TrueFalseTrueTrueTrueTrueTrueTrueFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent19TrueTrueTrueTrueTrueTrueTrueTrueTrueFalse...TrueTrueFalseFalseFalseFalseTrueFalseFalseFalse
advent20TrueTrueFalseFalseFalseTrueFalseTrueFalseFalse...FalseFalseFalseFalseFalseTrueFalseFalseFalseFalse
advent21TrueFalseTrueTrueTrueTrueFalseFalseTrueFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent22TrueFalseFalseFalseFalseTrueFalseTrueFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseTrue
advent23TrueFalseFalseFalseFalseTrueTrueTrueFalseTrue...FalseFalseTrueFalseFalseFalseFalseFalseFalseFalse
advent24TrueTrueFalseFalseFalseTrueTrueTrueFalseTrue...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
advent25TrueTrueFalseFalseFalseFalseFalseFalseFalseFalse...FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse
\n", + "

25 rows × 35 columns

\n", + "
" + ], + "text/plain": [ + " AoC Data.List Data.Text Data.Attoparsec.Text Data.Text.IO \\\n", + "advent01 True True False False False \n", + "advent02 True False True True True \n", + "advent03 True True False False False \n", + "advent04 True False True True True \n", + "advent05 True True True True True \n", + "advent06 True True False False False \n", + "advent07 True True True True True \n", + "advent08 True True False False False \n", + "advent09 True True True True True \n", + "advent10 True True True True True \n", + "advent11 True True True True True \n", + "advent12 True False False False False \n", + "advent13 True True True True True \n", + "advent14 True True True True True \n", + "advent15 True False True True True \n", + "advent16 True True True True True \n", + "advent17 True False False False False \n", + "advent18 True False True True True \n", + "advent19 True True True True True \n", + "advent20 True True False False False \n", + "advent21 True False True True True \n", + "advent22 True False False False False \n", + "advent23 True False False False False \n", + "advent24 True True False False False \n", + "advent25 True True False False False \n", + "\n", + " Control.Lens Data.Set Data.Maybe Control.Applicative Linear \\\n", + "advent01 False False False False False \n", + "advent02 False False False True False \n", + "advent03 False True False False False \n", + "advent04 False False False False False \n", + "advent05 False False True True False \n", + "advent06 False False False False False \n", + "advent07 False False True True False \n", + "advent08 False False False False False \n", + "advent09 True True False True True \n", + "advent10 False False False True False \n", + "advent11 True False False True False \n", + "advent12 True True False False True \n", + "advent13 False False False True False \n", + "advent14 True True True False True \n", + "advent15 False True False False True \n", + "advent16 True True False True False \n", + "advent17 True True True False True \n", + "advent18 True True True False True \n", + "advent19 True True True True False \n", + "advent20 True False True False False \n", + "advent21 True False False True False \n", + "advent22 True False True False True \n", + "advent23 True True True False True \n", + "advent24 True True True False True \n", + "advent25 False False False False False \n", + "\n", + " ... GHC.Generics Control.DeepSeq Data.Monoid Data.IntMap \\\n", + "advent01 ... False False False False \n", + "advent02 ... False False False False \n", + "advent03 ... False False False False \n", + "advent04 ... False False False False \n", + "advent05 ... False False False False \n", + "advent06 ... False False False False \n", + "advent07 ... False False False False \n", + "advent08 ... False False False False \n", + "advent09 ... False False False False \n", + "advent10 ... False False False False \n", + "advent11 ... False False False True \n", + "advent12 ... False False False False \n", + "advent13 ... False False False False \n", + "advent14 ... False False False False \n", + "advent15 ... False False False False \n", + "advent16 ... False False False False \n", + "advent17 ... False False False False \n", + "advent18 ... False False False False \n", + "advent19 ... True True False False \n", + "advent20 ... False False False False \n", + "advent21 ... False False False False \n", + "advent22 ... False False False False \n", + "advent23 ... False False True False \n", + "advent24 ... False False False False \n", + "advent25 ... False False False False \n", + "\n", + " Data.Foldable Data.CircularList Control.Parallel.Strategies \\\n", + "advent01 False False False \n", + "advent02 False False False \n", + "advent03 False False False \n", + "advent04 False False False \n", + "advent05 False False False \n", + "advent06 False False False \n", + "advent07 False False False \n", + "advent08 False False False \n", + "advent09 False False False \n", + "advent10 False False False \n", + "advent11 False False False \n", + "advent12 True False False \n", + "advent13 False False False \n", + "advent14 False False False \n", + "advent15 False False False \n", + "advent16 False False False \n", + "advent17 False False False \n", + "advent18 False False False \n", + "advent19 False False True \n", + "advent20 False True False \n", + "advent21 False False False \n", + "advent22 False False False \n", + "advent23 False False False \n", + "advent24 False False False \n", + "advent25 False False False \n", + "\n", + " Control.Monad.Writer Control.Monad.RWS.Strict Prelude \n", + "advent01 False False False \n", + "advent02 False False False \n", + "advent03 False False False \n", + "advent04 False False False \n", + "advent05 False False False \n", + "advent06 False False False \n", + "advent07 False False False \n", + "advent08 False False False \n", + "advent09 False False False \n", + "advent10 False False False \n", + "advent11 True True False \n", + "advent12 False False False \n", + "advent13 False False False \n", + "advent14 False False False \n", + "advent15 False False False \n", + "advent16 False False False \n", + "advent17 False False False \n", + "advent18 False False False \n", + "advent19 False False False \n", + "advent20 False False False \n", + "advent21 False False False \n", + "advent22 False False True \n", + "advent23 False False False \n", + "advent24 False False False \n", + "advent25 False False False \n", + "\n", + "[25 rows x 35 columns]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "imports_sorted_cols = imports_df[sorted_imports]\n", + "imports_sorted_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "4b70002e-f12e-4067-b8b8-119504e4d86b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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aROIZY1TwHfA+hrzunXrLjuvuz73sLzSIV3xY2YeqjSvW7fusvO663MD9nRIR0TEdmAVsIuRRxZn5s7S87p16+7WXfNn1z0/9xBXr0hXrAR+AzaN7Etg3AG6kHndunWXndddnxvwSoeIiIj0hD0d0gkRcXNEvB8R3wy2b42IZ2rI69atu+y87vrcM7TtRLWs8xXwIXAHI4/JpXk7ZPF53bp1l53XXZ97WF7pkK5Ynpmfztn3dyV53bp1l53XXZ8b8PaKdMfJiFhL02hERGymeZRuDXndunWXndddn7th0ksjljVOATcC79F0Ox8HPgZuqCGvW7fusvO663MPy9Ur0gkRcXlmnouIq4DLMvNMLXndunWXndddn3uIt1ekK45GxCvAncAvleV169Zddl53fW7ASYd0xy00l+IeoxmsL0fEXZXkdevWXXZed33uhknvx1jWpAVcB7wGnKstr1u37rLzuutye6VDOiMiNkTEDuALYBnwQC153bp1l53XXZ8bfAy6dEREHAW+BN4Cdmfmr7XkdevWXXZed33umfM46ZAuiIiVmXm6xrxu3brLzuuuzz1zHicdMk0i4iUGD485H5n5RKl53bp1+xvVPV33XOzpkGnzGfA5zf2+24Ejg7oNOFd4Xrdu3d26a/7suufnns18ul4t61IF7AWWjmwvBfbWkNetW3fZed31uYfllQ7pitXAipHtqwf7asjr1q277Lzu+twALJk0IDImzwEHImLvYHsDsK2SvG7dusvO667PDdhIKh0SEauBrcAhYDlwIjM/qiGvW7fusvO663MD9nRY3RTwCPA1cIrmXuDvwAc15HXr1l12Xnd97pnzTBqwrHFqMDiXAV8OttcBb9aQ161bd9l53fW5h2UjqXTF2cw8CxARV2bmYZoXBtWQ161bd9l53fW5ARtJpTuORcS1wC5gT0ScAk5UktetW3fZed31uQEbSaUHImIDcA3wTmb+WVNet27dZed11+V20iEiIiK9YE+HiIiI9IKTDhEREekFJx0iIiLSC046REREpBecdIiIiEgv/APSKC9C0fn4twAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.colors.ListedColormap(['white', 'blue'])\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", + "ax.imshow(imports_df.to_numpy().T, cmap=cmap)\n", + "plt.xticks(range(imports_df.index.size), labels=imports_df.index.values, rotation=90);\n", + "plt.yticks(range(imports_df.columns.size), labels=imports_df.columns.values);\n", + "\n", + "ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5);\n", + "plt.savefig('imports.png');" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "280a262c-13d5-44c9-ab5f-9e166a76a2dc", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cmap = mpl.colors.ListedColormap(['white', 'blue'])\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", + "ax.imshow(imports_sorted_cols.to_numpy().T, cmap=cmap)\n", + "plt.xticks(range(imports_sorted_cols.index.size), labels=imports_sorted_cols.index.values, rotation=90);\n", + "plt.yticks(range(imports_sorted_cols.columns.size), labels=imports_sorted_cols.columns.values);\n", + "\n", + "ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5))\n", + "ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5);\n", + "plt.savefig('imports_sorted.png');" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "id": "684eb890-3729-4d68-a862-798c9ca152ce", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'3.4.2'" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import matplotlib as mpl\n", + "mpl.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c6ccc03-f87d-437f-aecf-e6cf1fcd0698", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,md" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/profiling/modules.md b/profiling/modules.md new file mode 100644 index 0000000..7af56ce --- /dev/null +++ b/profiling/modules.md @@ -0,0 +1,232 @@ +--- +jupyter: + jupytext: + formats: ipynb,md + text_representation: + extension: .md + format_name: markdown + format_version: '1.3' + jupytext_version: 1.11.1 + kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +```python +import os, glob +import collections +import pandas as pd +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +%matplotlib inline +``` + +```python +with open('../advent-of-code22.cabal') as f: + build_depends = [l for l in f.readlines() if 'build-depends' in l] +build_depends +``` + +```python +cabal_file = open('../advent-of-code22.cabal').read() +executables = cabal_file.split('executable')[2:] +executables[:3] +``` + +```python +e = executables[1] +e.strip().split('build-depends: ')[1].split(',') +``` + +```python +def extract(line): + parts = line.strip().split('build-depends: ') + name = parts[0].split()[0] + if len(parts) > 1: + depends = [p.strip() for p in parts[1].split('\n')[0].split(',') if 'base' not in p] + else: + depends = [] + return name, depends +``` + +```python +modules = {e: ms for e, ms in [extract(e) for e in executables] if e.endswith(tuple(str(i) for i in range(10)))} +modules +``` + +```python +all_modules = set(m for p in modules for m in modules[p]) +modules_df = pd.DataFrame.from_dict({p: {m: m in modules[p] for m in sorted(all_modules)} for p in modules}, orient='index').sort_index() +modules_df +``` + +```python +print(modules_df.sum().sort_values(ascending=False).to_markdown()) +``` + +```python tags=[] +sorted_modules = modules_df.sum().sort_values(ascending=False).index.values +sorted_modules +``` + +```python tags=[] +modules_sorted_cols = modules_df[sorted_modules] +modules_sorted_cols +``` + +```python +modules_scatter = modules_df.stack().reset_index() +modules_scatter.columns = ['program', 'module', 'present'] +modules_scatter = modules_scatter[modules_scatter.present] +modules_scatter +``` + +```python tags=[] +modules_scatter.plot.scatter(x='program', y='module', s=80, rot=45, figsize=(10, 6)) +``` + +```python +cmap = mpl.colors.ListedColormap(['white', 'blue']) + +fig, ax = plt.subplots(figsize=(10, 10)) +ax.imshow(modules_df.to_numpy().T, cmap=cmap) +plt.xticks(range(modules_df.index.size), labels=modules_df.index.values, rotation=90); +plt.yticks(range(modules_df.columns.size), labels=modules_df.columns.values); + +ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5); +plt.savefig('packages.png'); +``` + +```python +cmap = mpl.colors.ListedColormap(['white', 'blue']) + +fig, ax = plt.subplots(figsize=(10, 10)) +ax.imshow(modules_sorted_cols.to_numpy().T, cmap=cmap) +plt.xticks(range(modules_sorted_cols.index.size), labels=modules_sorted_cols.index.values, rotation=90); +plt.yticks(range(modules_sorted_cols.columns.size), labels=modules_sorted_cols.columns.values); + +ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5); +plt.savefig('packages_sorted.png'); +``` + +```python +mains = list(sorted(f for f in glob.glob('../advent*/Main.hs'))) +mains +``` + +```python +main_imports = {} + +for m in mains: + with open(m) as f: + lines = f.readlines() + import_lines = [l for l in lines if l.strip().startswith('import') if 'Debug.Trace' not in l] + imports = [] + for i in import_lines: + words = i.strip().split() + if 'qualified' in i: + imports.append((words[2], True)) + else: + imports.append((words[1], False)) + main_imports[m.split('/')[1]] = imports + +main_imports +``` + +```python +import_counts = collections.Counter(l for ls in main_imports.values() for l in ls) +import_counts.most_common() +``` + +```python +main_imports_unqualified = {m: set(i[0] for i in main_imports[m]) for m in main_imports} +main_imports_unqualified +``` + +```python +import_counts_unqualified = collections.Counter(l for ls in main_imports_unqualified.values() for l in ls) +import_counts_unqualified.most_common() +``` + +```python +all_imports = set(m for p in main_imports_unqualified for m in main_imports_unqualified[p]) +imports_df = pd.DataFrame.from_dict( + {p: {m: m in main_imports_unqualified[p] + for m in sorted(all_imports)} + for p in main_imports_unqualified}, + orient='index').sort_index() +imports_df +``` + +```python +print(imports_df.sum().sort_values(ascending=False).to_markdown()) +``` + +```python +imports_scatter = imports_df.stack().reset_index() +imports_scatter.columns = ['program', 'module', 'present'] +imports_scatter = imports_scatter[imports_scatter.present] +imports_scatter +``` + +```python tags=[] +imports_scatter.plot.scatter(x='program', y='module', s=80, rot=45, figsize=(10, 10)) +``` + +```python +imports_df.columns.size +``` + +```python tags=[] +sorted_imports = imports_df.sum().sort_values(ascending=False).index.values +sorted_imports +``` + +```python tags=[] +imports_sorted_cols = imports_df[sorted_imports] +imports_sorted_cols +``` + +```python +cmap = mpl.colors.ListedColormap(['white', 'blue']) + +fig, ax = plt.subplots(figsize=(10, 10)) +ax.imshow(imports_df.to_numpy().T, cmap=cmap) +plt.xticks(range(imports_df.index.size), labels=imports_df.index.values, rotation=90); +plt.yticks(range(imports_df.columns.size), labels=imports_df.columns.values); + +ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5); +plt.savefig('imports.png'); +``` + +```python +cmap = mpl.colors.ListedColormap(['white', 'blue']) + +fig, ax = plt.subplots(figsize=(10, 10)) +ax.imshow(imports_sorted_cols.to_numpy().T, cmap=cmap) +plt.xticks(range(imports_sorted_cols.index.size), labels=imports_sorted_cols.index.values, rotation=90); +plt.yticks(range(imports_sorted_cols.columns.size), labels=imports_sorted_cols.columns.values); + +ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.5)) +ax.grid(which='minor', axis='both', linestyle='-', color='silver', linewidth=1.5); +plt.savefig('imports_sorted.png'); +``` + +```python +import matplotlib as mpl +mpl.__version__ +``` + +```python + +``` diff --git a/profiling/modules.png b/profiling/modules.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2fde50d90dba24192dc40e671e59b08a70079 GIT binary patch literal 16380 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 literal 0 HcmV?d00001 diff --git a/profiling/packages_sorted.png b/profiling/packages_sorted.png new file mode 100644 index 0000000000000000000000000000000000000000..2988b77ad2b29ba80d7a7a57c6e5f323bca3a71a GIT binary patch literal 16981 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 literal 0 HcmV?d00001 diff --git a/profiling/performance.csv b/profiling/performance.csv new file mode 100644 index 0000000..92bd582 --- /dev/null +++ b/profiling/performance.csv @@ -0,0 +1,26 @@ +program,total_alloc,memory,elapsed +advent01,11516576,10488,0.02 +advent02,9613016,11112,0.02 +advent03,6018112,10408,0.02 +advent04,2913824,9040,0.01 +advent05,3396888,9324,0.01 +advent06,5025888,10124,0.02 +advent07,3049136,9192,0.01 +advent08,214597512,12204,0.09 +advent09,39708256,23660,0.06 +advent10,631808,6800,0.01 +advent11,655812832,66664,0.36 +advent12,1598902400,13264,1.09 +advent13,10281760,12300,0.01 +advent14,258169680,15068,0.85 +advent15,126607950592,18101260,137.27 +advent16,296137053800,45628,144.64 +advent17,77649009464,22000,20.67 +advent18,68244096,14060,0.06 +advent19,1964531122296,14295324,1134.12 +advent20,55860434768,13940,15.04 +advent21,351135824,12680,0.4 +advent22,528445105288,15908,0.23 +advent23,26387446504,13628,370.18 +advent24,3268072336,74820,2.74 +advent25,642496,5896,0.01 diff --git a/profiling/performance.md b/profiling/performance.md new file mode 100644 index 0000000..d224b26 --- /dev/null +++ b/profiling/performance.md @@ -0,0 +1,27 @@ +| Program | Total allocations | Max memory | Time | +|----------|------------------:|-----------:|-----:| +| advent01 | 107029176 | 72440 | 0.04 | +| advent02 | 35370072 | 72440 | 0.06 | +| advent03 | 4017640 | 72504 | 0.02 | +| advent04 | 60820368 | 72504 | 0.08 | +| advent05 | 27810256 | 72440 | 0.08 | +| advent06 | 11624856 | 72504 | 0.06 | +| advent07 | 21605440 | 72444 | 0.04 | +| advent08 | 74894192 | 72508 | 0.09 | +| advent09 | 793279616 | 72508 | 0.31 | +| advent10 | 924456 | 72444 | 0.01 | +| advent11 | 35282262592 | 72504 | 16.4 | +| advent12 | 2206400 | 72508 | 0.03 | +| advent13 | 542152 | 72436 | 0.01 | +| advent14 | 259113488 | 72508 | 0.26 | +| advent15 | 6662932672 | 240372 | 1.80 | +| advent16 | 17242880 | 72444 | 0.03 | +| advent17 | 4808712520 | 72444 | 1.42 | +| advent18 | 21509984 | 72444 | 0.04 | +| advent19 | 44456496 | 72504 | 0.11 | +| advent20 | 3860804096 | 72436 | 3.77 | +| advent21 | 9561880 | 72508 | 0.04 | +| advent22 | 3242847728 | 72500 | 1.67 | +| advent23 | 10263690000 | 95500 | 1.56 | +| advent24 | 4352105528 | 72504 | 3.13 | +| advent25 | 39231576 | 72504 | 0.06 | diff --git a/profiling/profiling.ipynb b/profiling/profiling.ipynb new file mode 100644 index 0000000..142d6de --- /dev/null +++ b/profiling/profiling.ipynb @@ -0,0 +1,4081 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 201, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "import glob\n", + "import json\n", + "import pandas as pd\n", + "import numpy as np\n", + "import datetime\n", + "import re\n", + "\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "! cd .. && cabal install" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false", + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - split-0.2.3.5 (lib) (requires build)\n", + " - advent-of-code22-0.1.0.0 (exe:advent01) --enable-profiling (configuration changed)\n", + "Starting split-0.2.3.5 (lib)\n", + "Building split-0.2.3.5 (lib)\n", + "Installing split-0.2.3.5 (lib)\n", + "Completed split-0.2.3.5 (lib)\n", + "Configuring executable 'advent01' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent01' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent01' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent01/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent01/build/advent01/advent01-tmp/Main.dyn_o ) [Data.List.Split changed]\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent01/build/advent01/advent01-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent01/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent01/build/advent01/advent01-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent01/build/advent01/advent01 ...\n", + "66719\n", + "198551\n", + " 19,449,616 bytes allocated in the heap\n", + " 1,325,784 bytes copied during GC\n", + " 408,784 bytes maximum residency (2 sample(s))\n", + " 144,176 bytes maximum slop\n", + " 63 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 3 colls, 3 par 0.002s 0.001s 0.0003s 0.0003s\n", + " Gen 1 2 colls, 1 par 0.002s 0.001s 0.0004s 0.0005s\n", + "\n", + " Parallel GC work balance: 29.84% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.013s ( 0.012s elapsed)\n", + " GC time 0.004s ( 0.002s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.023s ( 0.017s elapsed)\n", + "\n", + " Alloc rate 1,512,211,092 bytes per MUT second\n", + "\n", + " Productivity 56.0% of total user, 69.2% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - attoparsec-0.14.4 (lib:attoparsec-internal) (requires build)\n", + " - attoparsec-0.14.4 (lib) (requires build)\n", + " - advent-of-code22-0.1.0.0 (exe:advent02) --enable-profiling (configuration changed)\n", + "Starting attoparsec-0.14.4 (lib:attoparsec-internal)\n", + "Building attoparsec-0.14.4 (lib:attoparsec-internal)\n", + "Installing attoparsec-0.14.4 (lib:attoparsec-internal)\n", + "Completed attoparsec-0.14.4 (lib:attoparsec-internal)\n", + "Starting attoparsec-0.14.4 (lib)\n", + "Building attoparsec-0.14.4 (lib)\n", + "Installing attoparsec-0.14.4 (lib)\n", + "Completed attoparsec-0.14.4 (lib)\n", + "Configuring executable 'advent02' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent02' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent02' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent02/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent02/build/advent02/advent02-tmp/Main.dyn_o ) [Data.Attoparsec.Text changed]\n", + "\n", + "\u001b[;1madvent02/Main.hs:55:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " match1P :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text [Round]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m55 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmatch1P\u001b[0m\u001b[0m = roundP `sepBy` endOfLine\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:56:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " roundP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Round\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m56 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mroundP\u001b[0m\u001b[0m = Round <$> p1ShapeP <*> (\" \" *> p2ShapeP)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:58:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " match2P :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text [ShapeResult]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m58 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmatch2P\u001b[0m\u001b[0m = shapeResultP `sepBy` endOfLine\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:59:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " shapeResultP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text ShapeResult\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m59 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mshapeResultP\u001b[0m\u001b[0m = ShapeResult <$> p1ShapeP <*> (\" \" *> resultP)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:61:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " p1ShapeP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m61 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mp1ShapeP\u001b[0m\u001b[0m = aP <|> bP <|> cP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:62:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " aP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m62 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35maP\u001b[0m\u001b[0m = Rock <$ \"A\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:63:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " bP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m63 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mbP\u001b[0m\u001b[0m = Paper <$ \"B\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:64:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " cP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m64 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mcP\u001b[0m\u001b[0m = Scissors <$ \"C\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:66:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " p2ShapeP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m66 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mp2ShapeP\u001b[0m\u001b[0m = xP <|> yP <|> zP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:67:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " xP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m67 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mxP\u001b[0m\u001b[0m = Rock <$ \"X\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:68:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " yP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m68 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35myP\u001b[0m\u001b[0m = Paper <$ \"Y\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:69:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " zP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m69 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mzP\u001b[0m\u001b[0m = Scissors <$ \"Z\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:71:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " resultP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m71 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mresultP\u001b[0m\u001b[0m = xrP <|> yrP <|> zrP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:72:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " xrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m72 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mxrP\u001b[0m\u001b[0m = Loss <$ \"X\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:73:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " yrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m73 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35myrP\u001b[0m\u001b[0m = Draw <$ \"Y\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:74:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " zrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mzrP\u001b[0m\u001b[0m = Win <$ \"Z\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:77:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " successfulParse1 :: Data.Text.Internal.Text -> [Round]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m77 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msuccessfulParse1\u001b[0m\u001b[0m input = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:80:11: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘match’ shadows the existing binding\n", + " imported from ‘Data.Attoparsec.Text’ at advent02/Main.hs:6:1-43\n", + " (and originally defined in ‘attoparsec-0.14.4-6c5af65faab69e2a5d91c97faaf49696df50d10719db2c6a1db14bb260536cd8:Data.Attoparsec.Text.Internal’)\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m80 |\u001b[0m\u001b[0m Right \u001b[;1m\u001b[35mmatch\u001b[0m\u001b[0m -> match\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:82:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " successfulParse2 :: Data.Text.Internal.Text -> [ShapeResult]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m82 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msuccessfulParse2\u001b[0m\u001b[0m input = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:85:11: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘match’ shadows the existing binding\n", + " imported from ‘Data.Attoparsec.Text’ at advent02/Main.hs:6:1-43\n", + " (and originally defined in ‘attoparsec-0.14.4-6c5af65faab69e2a5d91c97faaf49696df50d10719db2c6a1db14bb260536cd8:Data.Attoparsec.Text.Internal’)\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m85 |\u001b[0m\u001b[0m Right \u001b[;1m\u001b[35mmatch\u001b[0m\u001b[0m -> match\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent02/build/advent02/advent02-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent02/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent02/build/advent02/advent02-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent02/Main.hs:55:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " match1P :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text [Round]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m55 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmatch1P\u001b[0m\u001b[0m = roundP `sepBy` endOfLine\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:56:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " roundP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Round\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m56 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mroundP\u001b[0m\u001b[0m = Round <$> p1ShapeP <*> (\" \" *> p2ShapeP)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:58:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " match2P :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text [ShapeResult]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m58 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmatch2P\u001b[0m\u001b[0m = shapeResultP `sepBy` endOfLine\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:59:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " shapeResultP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text ShapeResult\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m59 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mshapeResultP\u001b[0m\u001b[0m = ShapeResult <$> p1ShapeP <*> (\" \" *> resultP)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:61:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " p1ShapeP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m61 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mp1ShapeP\u001b[0m\u001b[0m = aP <|> bP <|> cP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:62:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " aP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m62 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35maP\u001b[0m\u001b[0m = Rock <$ \"A\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:63:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " bP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m63 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mbP\u001b[0m\u001b[0m = Paper <$ \"B\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:64:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " cP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m64 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mcP\u001b[0m\u001b[0m = Scissors <$ \"C\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:66:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " p2ShapeP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m66 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mp2ShapeP\u001b[0m\u001b[0m = xP <|> yP <|> zP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:67:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " xP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m67 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mxP\u001b[0m\u001b[0m = Rock <$ \"X\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:68:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " yP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m68 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35myP\u001b[0m\u001b[0m = Paper <$ \"Y\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:69:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " zP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Shape\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m69 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mzP\u001b[0m\u001b[0m = Scissors <$ \"Z\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:71:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " resultP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m71 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mresultP\u001b[0m\u001b[0m = xrP <|> yrP <|> zrP\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:72:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " xrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m72 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mxrP\u001b[0m\u001b[0m = Loss <$ \"X\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:73:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " yrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m73 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35myrP\u001b[0m\u001b[0m = Draw <$ \"Y\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:74:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " zrP :: Data.Attoparsec.Internal.Types.Parser\n", + " Data.Text.Internal.Text Result\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mzrP\u001b[0m\u001b[0m = Win <$ \"Z\"\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:77:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " successfulParse1 :: Data.Text.Internal.Text -> [Round]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m77 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msuccessfulParse1\u001b[0m\u001b[0m input = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:80:11: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘match’ shadows the existing binding\n", + " imported from ‘Data.Attoparsec.Text’ at advent02/Main.hs:6:1-43\n", + " (and originally defined in ‘attoparsec-0.14.4-6c5af65faab69e2a5d91c97faaf49696df50d10719db2c6a1db14bb260536cd8:Data.Attoparsec.Text.Internal’)\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m80 |\u001b[0m\u001b[0m Right \u001b[;1m\u001b[35mmatch\u001b[0m\u001b[0m -> match\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:82:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wmissing-signatures\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Top-level binding with no type signature:\n", + " successfulParse2 :: Data.Text.Internal.Text -> [ShapeResult]\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m82 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msuccessfulParse2\u001b[0m\u001b[0m input = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent02/Main.hs:85:11: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘match’ shadows the existing binding\n", + " imported from ‘Data.Attoparsec.Text’ at advent02/Main.hs:6:1-43\n", + " (and originally defined in ‘attoparsec-0.14.4-6c5af65faab69e2a5d91c97faaf49696df50d10719db2c6a1db14bb260536cd8:Data.Attoparsec.Text.Internal’)\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m85 |\u001b[0m\u001b[0m Right \u001b[;1m\u001b[35mmatch\u001b[0m\u001b[0m -> match\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent02/build/advent02/advent02 ...\n", + "13009\n", + "10398\n", + " 15,142,040 bytes allocated in the heap\n", + " 1,016,576 bytes copied during GC\n", + " 294,736 bytes maximum residency (2 sample(s))\n", + " 143,536 bytes maximum slop\n", + " 63 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 2 colls, 2 par 0.001s 0.001s 0.0004s 0.0004s\n", + " Gen 1 2 colls, 1 par 0.002s 0.001s 0.0003s 0.0003s\n", + "\n", + " Parallel GC work balance: 31.81% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.014s ( 0.013s elapsed)\n", + " GC time 0.003s ( 0.001s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.023s ( 0.017s elapsed)\n", + "\n", + " Alloc rate 1,119,000,702 bytes per MUT second\n", + "\n", + " Productivity 59.2% of total user, 73.6% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent03) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent03' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent03' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent03' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent03/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent03/build/advent03/advent03-tmp/Main.dyn_o ) [Data.List.Split changed]\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent03/build/advent03/advent03-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent03/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent03/build/advent03/advent03-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent03/build/advent03/advent03 ...\n", + "7727\n", + "2609\n", + " 9,004,224 bytes allocated in the heap\n", + " 886,400 bytes copied during GC\n", + " 214,088 bytes maximum residency (1 sample(s))\n", + " 121,784 bytes maximum slop\n", + " 62 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 2 colls, 2 par 0.002s 0.001s 0.0006s 0.0010s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0003s 0.0003s\n", + "\n", + " Parallel GC work balance: 24.28% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.007s ( 0.006s elapsed)\n", + " GC time 0.002s ( 0.002s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.015s ( 0.011s elapsed)\n", + "\n", + " Alloc rate 1,362,247,646 bytes per MUT second\n", + "\n", + " Productivity 43.5% of total user, 54.5% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent04) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent04' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent04' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent04' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent04/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent04/build/advent04/advent04-tmp/Main.dyn_o ) [Data.Attoparsec.Text changed]\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent04/build/advent04/advent04-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent04/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent04/build/advent04/advent04-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent04/build/advent04/advent04 ...\n", + "513\n", + "878\n", + " 4,443,080 bytes allocated in the heap\n", + " 164,040 bytes copied during GC\n", + " 223,280 bytes maximum residency (1 sample(s))\n", + " 124,880 bytes maximum slop\n", + " 62 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 0 colls, 0 par 0.000s 0.000s 0.0000s 0.0000s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0003s 0.0003s\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.005s ( 0.003s elapsed)\n", + " MUT time 0.005s ( 0.005s elapsed)\n", + " GC time 0.000s ( 0.000s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.013s ( 0.009s elapsed)\n", + "\n", + " Alloc rate 853,932,014 bytes per MUT second\n", + "\n", + " Productivity 40.5% of total user, 54.6% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent05) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent05' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent05' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent05' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent05/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent05/build/advent05/advent05-tmp/Main.dyn_o ) [Data.Attoparsec.Text changed]\n", + "\n", + "\u001b[;1madvent05/Main.hs:54:9: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-uni-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In a pattern binding: Patterns of type ‘[Crate]’ not matched: []\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m54 |\u001b[0m\u001b[0m where \u001b[;1m\u001b[35m(c:origin) = wharf!from\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent05/build/advent05/advent05-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent05/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent05/build/advent05/advent05-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent05/Main.hs:54:9: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-uni-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In a pattern binding: Patterns of type ‘[Crate]’ not matched: []\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m54 |\u001b[0m\u001b[0m where \u001b[;1m\u001b[35m(c:origin) = wharf!from\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent05/build/advent05/advent05 ...\n", + "TGWSMRBPN\n", + "TZLTLWRNF\n", + " 5,094,344 bytes allocated in the heap\n", + " 425,056 bytes copied during GC\n", + " 214,088 bytes maximum residency (1 sample(s))\n", + " 125,880 bytes maximum slop\n", + " 62 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 1 colls, 1 par 0.001s 0.000s 0.0003s 0.0003s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0003s 0.0003s\n", + "\n", + " Parallel GC work balance: 49.39% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.005s ( 0.004s elapsed)\n", + " GC time 0.001s ( 0.001s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.012s ( 0.008s elapsed)\n", + "\n", + " Alloc rate 1,061,113,423 bytes per MUT second\n", + "\n", + " Productivity 40.8% of total user, 53.4% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent06) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent06' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent06' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent06' for advent-of-code22-0.1.0.0..\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent06/build/advent06/advent06-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent06/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent06/build/advent06/advent06-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent06/build/advent06/advent06 ...\n", + "1080\n", + "3645\n", + " 7,728,352 bytes allocated in the heap\n", + " 340,432 bytes copied during GC\n", + " 231,824 bytes maximum residency (1 sample(s))\n", + " 132,720 bytes maximum slop\n", + " 61 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 1 colls, 1 par 0.001s 0.000s 0.0002s 0.0002s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0003s 0.0003s\n", + "\n", + " Parallel GC work balance: 57.64% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.003s elapsed)\n", + " MUT time 0.004s ( 0.004s elapsed)\n", + " GC time 0.001s ( 0.000s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.012s ( 0.008s elapsed)\n", + "\n", + " Alloc rate 1,749,470,406 bytes per MUT second\n", + "\n", + " Productivity 37.0% of total user, 50.2% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - rosezipper-0.2 (lib:rosezipper) (requires build)\n", + " - advent-of-code22-0.1.0.0 (exe:advent07) --enable-profiling (configuration changed)\n", + "Starting rosezipper-0.2 (all, legacy fallback)\n", + "Building rosezipper-0.2 (all, legacy fallback)\n", + "Installing rosezipper-0.2 (all, legacy fallback)\n", + "Completed rosezipper-0.2 (all, legacy fallback)\n", + "Configuring executable 'advent07' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent07' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent07' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent07/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent07/build/advent07/advent07-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent07/build/advent07/advent07-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent07/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent07/build/advent07/advent07-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent07/build/advent07/advent07 ...\n", + "1084134\n", + "6183184\n", + " 4,838,856 bytes allocated in the heap\n", + " 510,704 bytes copied during GC\n", + " 214,088 bytes maximum residency (1 sample(s))\n", + " 125,880 bytes maximum slop\n", + " 63 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 1 colls, 1 par 0.001s 0.000s 0.0005s 0.0005s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0004s 0.0004s\n", + "\n", + " Parallel GC work balance: 41.61% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.006s ( 0.006s elapsed)\n", + " GC time 0.001s ( 0.001s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.013s ( 0.010s elapsed)\n", + "\n", + " Alloc rate 792,510,382 bytes per MUT second\n", + "\n", + " Productivity 45.7% of total user, 56.1% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent08) --enable-profiling (first run)\n", + "Configuring executable 'advent08' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent08' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent08' for advent-of-code22-0.1.0.0..\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent08/build/advent08/advent08-tmp/AoC.dyn_o )\n", + "[2 of 2] Compiling Main ( advent08/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent08/build/advent08/advent08-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent08/build/advent08/advent08-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent08/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent08/build/advent08/advent08-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent08/build/advent08/advent08 ...\n", + "1823\n", + "211680\n", + " 351,652,392 bytes allocated in the heap\n", + " 11,062,736 bytes copied during GC\n", + " 1,485,704 bytes maximum residency (6 sample(s))\n", + " 138,792 bytes maximum slop\n", + " 63 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 80 colls, 80 par 0.077s 0.025s 0.0003s 0.0069s\n", + " Gen 1 6 colls, 5 par 0.016s 0.004s 0.0007s 0.0013s\n", + "\n", + " Parallel GC work balance: 45.01% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.005s ( 0.003s elapsed)\n", + " MUT time 0.174s ( 0.164s elapsed)\n", + " GC time 0.092s ( 0.029s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.001s ( 0.001s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.273s ( 0.197s elapsed)\n", + "\n", + " Alloc rate 2,024,427,305 bytes per MUT second\n", + "\n", + " Productivity 63.9% of total user, 83.3% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent09) --enable-profiling (first run)\n", + "Configuring executable 'advent09' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent09' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent09' for advent-of-code22-0.1.0.0..\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent09/build/advent09/advent09-tmp/AoC.dyn_o )\n", + "[2 of 2] Compiling Main ( advent09/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent09/build/advent09/advent09-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent09/build/advent09/advent09-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent09/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent09/build/advent09/advent09-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent09/build/advent09/advent09 ...\n", + "6243\n", + "2630\n", + " 59,497,800 bytes allocated in the heap\n", + " 40,326,560 bytes copied during GC\n", + " 8,220,544 bytes maximum residency (6 sample(s))\n", + " 2,878,880 bytes maximum slop\n", + " 77 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 7 colls, 7 par 0.029s 0.027s 0.0038s 0.0066s\n", + " Gen 1 6 colls, 5 par 0.054s 0.037s 0.0061s 0.0125s\n", + "\n", + " Parallel GC work balance: 7.47% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.041s ( 0.039s elapsed)\n", + " GC time 0.083s ( 0.063s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.131s ( 0.105s elapsed)\n", + "\n", + " Alloc rate 1,443,718,624 bytes per MUT second\n", + "\n", + " Productivity 31.6% of total user, 36.9% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent10) --enable-profiling (first run)\n", + "Configuring executable 'advent10' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent10' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent10' for advent-of-code22-0.1.0.0..\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent10/build/advent10/advent10-tmp/AoC.dyn_o )\n", + "[2 of 2] Compiling Main ( advent10/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent10/build/advent10/advent10-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent10/build/advent10/advent10-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent10/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent10/build/advent10/advent10-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent10/build/advent10/advent10 ...\n", + "15140\n", + "███ ███ ██ ██ ████ ██ ██ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ █ █ █ █ █ █ █ █ █ █ \n", + "█ █ ███ █ ████ █ █ ██ ████ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ ██ █ █ ████ ███ █ █ █ \n", + " \n", + "\n", + " 900,472 bytes allocated in the heap\n", + " 164,040 bytes copied during GC\n", + " 223,280 bytes maximum residency (1 sample(s))\n", + " 124,880 bytes maximum slop\n", + " 62 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 0 colls, 0 par 0.000s 0.000s 0.0000s 0.0000s\n", + " Gen 1 1 colls, 0 par 0.000s 0.000s 0.0005s 0.0005s\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.001s ( 0.001s elapsed)\n", + " GC time 0.000s ( 0.000s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.008s ( 0.005s elapsed)\n", + "\n", + " Alloc rate 680,385,621 bytes per MUT second\n", + "\n", + " Productivity 16.9% of total user, 23.5% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent11) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent11' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent11' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent11' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent11/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent11/build/advent11/advent11-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent11/Main.hs:89:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In an equation for ‘updateWorry’:\n", + " Patterns of type ‘Int’, ‘Expression’, ‘Int -> Int’ not matched:\n", + " _ (Expression Plus (Literal _)) _\n", + " _ (Expression Plus Old) _\n", + " _ (Expression Times (Literal _)) _\n", + " _ (Expression Times Old) _\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m89 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mupdateWorry current (Expression operator operand) threshold\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent11/build/advent11/advent11-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent11/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent11/build/advent11/advent11-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent11/Main.hs:89:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In an equation for ‘updateWorry’:\n", + " Patterns of type ‘Int’, ‘Expression’, ‘Int -> Int’ not matched:\n", + " _ (Expression Plus (Literal _)) _\n", + " _ (Expression Plus Old) _\n", + " _ (Expression Times (Literal _)) _\n", + " _ (Expression Times Old) _\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m89 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mupdateWorry current (Expression operator operand) threshold\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent11/build/advent11/advent11 ...\n", + "112815\n", + "25738411485\n", + " 1,017,483,040 bytes allocated in the heap\n", + " 383,219,896 bytes copied during GC\n", + " 59,332,752 bytes maximum residency (11 sample(s))\n", + " 748,528 bytes maximum slop\n", + " 179 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 231 colls, 231 par 0.216s 0.175s 0.0008s 0.0086s\n", + " Gen 1 11 colls, 10 par 0.733s 0.215s 0.0195s 0.0584s\n", + "\n", + " Parallel GC work balance: 49.26% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.003s elapsed)\n", + " MUT time 0.508s ( 0.467s elapsed)\n", + " GC time 0.860s ( 0.301s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.089s ( 0.088s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 1.464s ( 0.860s elapsed)\n", + "\n", + " Alloc rate 2,004,482,550 bytes per MUT second\n", + "\n", + " Productivity 40.8% of total user, 64.5% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - pqueue-1.4.3.0 (lib) (requires build)\n", + " - advent-of-code22-0.1.0.0 (exe:advent12) --enable-profiling (configuration changed)\n", + "Starting pqueue-1.4.3.0 (lib)\n", + "Building pqueue-1.4.3.0 (lib)\n", + "Installing pqueue-1.4.3.0 (lib)\n", + "Completed pqueue-1.4.3.0 (lib)\n", + "Configuring executable 'advent12' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent12' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent12' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent12/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent12/build/advent12/advent12-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent12/Main.hs:29:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘goal’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m29 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Mountain\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:39:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘cost’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m39 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:81:9: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m81 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m = grid0 // [(s, mkCell 'a'), (g, mkCell 'z')]\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:123:8: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m123 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:123:8: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘grid’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m123 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:134:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘goal’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m134 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgoal\u001b[0m\u001b[0m <- asks _goal\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:139:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m139 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:153:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘goal’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m153 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgoal\u001b[0m\u001b[0m <- asks _goal\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent12/build/advent12/advent12-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent12/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent12/build/advent12/advent12-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent12/Main.hs:29:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘goal’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m29 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Mountain\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:39:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘cost’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m39 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:81:9: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m81 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m = grid0 // [(s, mkCell 'a'), (g, mkCell 'z')]\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:123:8: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m123 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:123:8: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘grid’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m123 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:134:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘goal’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m134 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgoal\u001b[0m\u001b[0m <- asks _goal\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:139:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘grid’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m139 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgrid\u001b[0m\u001b[0m <- asks _grid\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent12/Main.hs:153:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘goal’ shadows the existing binding\n", + " defined at advent12/Main.hs:29:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m153 |\u001b[0m\u001b[0m do \u001b[;1m\u001b[35mgoal\u001b[0m\u001b[0m <- asks _goal\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent12/build/advent12/advent12 ...\n", + "468\n", + "459\n", + " 2,329,680,024 bytes allocated in the heap\n", + " 94,728,104 bytes copied during GC\n", + " 849,440 bytes maximum residency (43 sample(s))\n", + " 186,352 bytes maximum slop\n", + " 62 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 521 colls, 521 par 0.250s 0.156s 0.0003s 0.0014s\n", + " Gen 1 43 colls, 42 par 0.086s 0.028s 0.0007s 0.0016s\n", + "\n", + " Parallel GC work balance: 16.10% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.005s ( 0.003s elapsed)\n", + " MUT time 2.081s ( 1.966s elapsed)\n", + " GC time 0.331s ( 0.179s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.005s ( 0.005s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 2.423s ( 2.154s elapsed)\n", + "\n", + " Alloc rate 1,119,659,454 bytes per MUT second\n", + "\n", + " Productivity 86.0% of total user, 91.5% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent13) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent13' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent13' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent13' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent13/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent13/build/advent13/advent13-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent13/build/advent13/advent13-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent13/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent13/build/advent13/advent13-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent13/build/advent13/advent13 ...\n", + "5675\n", + "20383\n", + " 15,983,552 bytes allocated in the heap\n", + " 2,677,272 bytes copied during GC\n", + " 1,145,232 bytes maximum residency (2 sample(s))\n", + " 136,816 bytes maximum slop\n", + " 64 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 2 colls, 2 par 0.003s 0.002s 0.0011s 0.0011s\n", + " Gen 1 2 colls, 1 par 0.004s 0.001s 0.0007s 0.0010s\n", + "\n", + " Parallel GC work balance: 30.00% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.005s ( 0.003s elapsed)\n", + " MUT time 0.016s ( 0.016s elapsed)\n", + " GC time 0.007s ( 0.004s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.030s ( 0.023s elapsed)\n", + "\n", + " Alloc rate 975,509,592 bytes per MUT second\n", + "\n", + " Productivity 55.1% of total user, 67.1% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent14) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent14' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent14' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent14' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent14/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent14/build/advent14/advent14-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent14/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Applicative’ is redundant\n", + " except perhaps to import instances from ‘Control.Applicative’\n", + " To import instances alone, use: import Control.Applicative()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Applicative\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent14/build/advent14/advent14-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent14/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent14/build/advent14/advent14-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent14/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Applicative’ is redundant\n", + " except perhaps to import instances from ‘Control.Applicative’\n", + " To import instances alone, use: import Control.Applicative()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Applicative\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent14/build/advent14/advent14 ...\n", + "644\n", + "27324\n", + " 474,666,344 bytes allocated in the heap\n", + " 44,189,776 bytes copied during GC\n", + " 3,669,176 bytes maximum residency (17 sample(s))\n", + " 160,312 bytes maximum slop\n", + " 66 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 99 colls, 99 par 0.047s 0.027s 0.0003s 0.0009s\n", + " Gen 1 17 colls, 16 par 0.080s 0.028s 0.0017s 0.0031s\n", + "\n", + " Parallel GC work balance: 50.21% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.003s elapsed)\n", + " MUT time 1.617s ( 1.592s elapsed)\n", + " GC time 0.112s ( 0.040s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.015s ( 0.015s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 1.751s ( 1.650s elapsed)\n", + "\n", + " Alloc rate 293,505,646 bytes per MUT second\n", + "\n", + " Productivity 93.3% of total user, 97.4% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent15) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent15' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent15' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent15' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent15/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent15/build/advent15/advent15-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent15/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Applicative’ is redundant\n", + " except perhaps to import instances from ‘Control.Applicative’\n", + " To import instances alone, use: import Control.Applicative()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Applicative\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:8:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Data.List’ is redundant\n", + " except perhaps to import instances from ‘Data.List’\n", + " To import instances alone, use: import Data.List()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m8 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Data.List\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:12:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Lens’ is redundant\n", + " except perhaps to import instances from ‘Control.Lens’\n", + " To import instances alone, use: import Control.Lens()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m12 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Lens\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:25:21: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘p’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m25 |\u001b[0m\u001b[0m mempty = Region (\\\u001b[;1m\u001b[35mp\u001b[0m\u001b[0m -> False)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent15/build/advent15/advent15-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent15/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent15/build/advent15/advent15-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent15/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Applicative’ is redundant\n", + " except perhaps to import instances from ‘Control.Applicative’\n", + " To import instances alone, use: import Control.Applicative()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Applicative\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:8:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Data.List’ is redundant\n", + " except perhaps to import instances from ‘Data.List’\n", + " To import instances alone, use: import Data.List()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m8 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Data.List\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:12:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Control.Lens’ is redundant\n", + " except perhaps to import instances from ‘Control.Lens’\n", + " To import instances alone, use: import Control.Lens()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m12 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Control.Lens\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent15/Main.hs:25:21: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘p’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m25 |\u001b[0m\u001b[0m mempty = Region (\\\u001b[;1m\u001b[35mp\u001b[0m\u001b[0m -> False)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent15/build/advent15/advent15 ...\n", + "5147333\n", + "13734006908372\n", + " 189,084,295,488 bytes allocated in the heap\n", + "10,329,767,309,344 bytes copied during GC\n", + " 13,185,529,696 bytes maximum residency (1550 sample(s))\n", + " 64,387,232 bytes maximum slop\n", + " 25723 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 44034 colls, 44034 par 69.955s 59.862s 0.0014s 0.0142s\n", + " Gen 1 1550 colls, 1549 par 18709.588s 6375.071s 4.1129s 9.0665s\n", + "\n", + " Parallel GC work balance: 91.17% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.005s ( 0.003s elapsed)\n", + " MUT time 257.456s (161.075s elapsed)\n", + " GC time 14408.495s (2094.011s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 4371.048s (4340.921s elapsed)\n", + " EXIT time 1.473s ( 0.001s elapsed)\n", + " Total time 19038.476s (6596.011s elapsed)\n", + "\n", + " Alloc rate 734,434,270 bytes per MUT second\n", + "\n", + " Productivity 24.3% of total user, 68.3% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent16) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent16' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent16' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent16' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent16/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent16/build/advent16/advent16-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent16/Main.hs:58:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘benefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m58 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent16/build/advent16/advent16-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent16/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent16/build/advent16/advent16-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent16/Main.hs:58:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘benefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m58 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent16/build/advent16/advent16 ...\n", + "1792\n", + "2587\n", + " 436,836,396,688 bytes allocated in the heap\n", + " 48,620,803,928 bytes copied during GC\n", + " 20,171,424 bytes maximum residency (2171 sample(s))\n", + " 351,712 bytes maximum slop\n", + " 97 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 103284 colls, 103284 par 56.327s 37.400s 0.0004s 0.0132s\n", + " Gen 1 2171 colls, 2170 par 47.089s 15.604s 0.0072s 0.0351s\n", + "\n", + " Parallel GC work balance: 31.48% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 224.034s (206.413s elapsed)\n", + " GC time 93.183s ( 42.812s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 10.234s ( 10.192s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 327.457s (259.420s elapsed)\n", + "\n", + " Alloc rate 1,949,862,696 bytes per MUT second\n", + "\n", + " Productivity 71.5% of total user, 83.5% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent17) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent17' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent17' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent17' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent17/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent17/build/advent17/advent17-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent17/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The qualified import of ‘Data.Map.Strict’ is redundant\n", + " except perhaps to import instances from ‘Data.Map.Strict’\n", + " To import instances alone, use: import Data.Map.Strict()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport qualified Data.Map.Strict as M\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:70:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘simSome’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m70 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msimSome\u001b[0m\u001b[0m oneJetCycle n = fromMaybe -1 $ maximumOf (folded . _y) (final ^. chamber)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:74:10: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘rocks’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m simulate \u001b[;1m\u001b[35mrocks\u001b[0m\u001b[0m jets n = (!!n) $ iterate dropFromTop initState\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:74:16: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘jets’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m simulate rocks \u001b[;1m\u001b[35mjets\u001b[0m\u001b[0m n = (!!n) $ iterate dropFromTop initState\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:96:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m96 |\u001b[0m\u001b[0m push \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m rock direction \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:106:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m106 |\u001b[0m\u001b[0m fall \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m rock \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:143:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘showChamber’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m143 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mshowChamber\u001b[0m\u001b[0m chamber = unlines \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:143:13: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m143 |\u001b[0m\u001b[0m showChamber \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m = unlines \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent17/build/advent17/advent17-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent17/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent17/build/advent17/advent17-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent17/Main.hs:7:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The qualified import of ‘Data.Map.Strict’ is redundant\n", + " except perhaps to import instances from ‘Data.Map.Strict’\n", + " To import instances alone, use: import Data.Map.Strict()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m7 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport qualified Data.Map.Strict as M\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:70:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘simSome’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m70 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35msimSome\u001b[0m\u001b[0m oneJetCycle n = fromMaybe -1 $ maximumOf (folded . _y) (final ^. chamber)\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:74:10: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘rocks’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m simulate \u001b[;1m\u001b[35mrocks\u001b[0m\u001b[0m jets n = (!!n) $ iterate dropFromTop initState\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:74:16: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘jets’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m74 |\u001b[0m\u001b[0m simulate rocks \u001b[;1m\u001b[35mjets\u001b[0m\u001b[0m n = (!!n) $ iterate dropFromTop initState\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:96:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m96 |\u001b[0m\u001b[0m push \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m rock direction \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:106:6: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m106 |\u001b[0m\u001b[0m fall \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m rock \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:143:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘showChamber’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m143 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mshowChamber\u001b[0m\u001b[0m chamber = unlines \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent17/Main.hs:143:13: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘chamber’ shadows the existing binding\n", + " defined at advent17/Main.hs:22:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m143 |\u001b[0m\u001b[0m showChamber \u001b[;1m\u001b[35mchamber\u001b[0m\u001b[0m = unlines \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent17/build/advent17/advent17 ...\n", + "3211\n", + "1589142857183\n", + " 112,643,551,288 bytes allocated in the heap\n", + " 3,363,497,384 bytes copied during GC\n", + " 4,914,576 bytes maximum residency (500 sample(s))\n", + " 766,208 bytes maximum slop\n", + " 65 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 24300 colls, 24300 par 7.144s 3.060s 0.0001s 0.0112s\n", + " Gen 1 500 colls, 499 par 2.683s 1.091s 0.0022s 0.0114s\n", + "\n", + " Parallel GC work balance: 32.92% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 56.213s ( 52.282s elapsed)\n", + " GC time 9.185s ( 3.513s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.641s ( 0.638s elapsed)\n", + " EXIT time 0.003s ( 0.002s elapsed)\n", + " Total time 66.046s ( 56.437s elapsed)\n", + "\n", + " Alloc rate 2,003,871,640 bytes per MUT second\n", + "\n", + " Productivity 86.1% of total user, 93.8% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent18) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent18' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent18' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent18' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent18/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent18/build/advent18/advent18-tmp/Main.dyn_o )\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent18/build/advent18/advent18-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent18/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent18/build/advent18/advent18-tmp/Main.p_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent18/build/advent18/advent18 ...\n", + "3364\n", + "2006\n", + " 101,387,336 bytes allocated in the heap\n", + " 7,046,080 bytes copied during GC\n", + " 1,772,120 bytes maximum residency (3 sample(s))\n", + " 198,056 bytes maximum slop\n", + " 64 MiB total memory in use (0 MB lost due to fragmentation)\n", + "\n", + " Tot time (elapsed) Avg pause Max pause\n", + " Gen 0 22 colls, 22 par 0.011s 0.007s 0.0003s 0.0015s\n", + " Gen 1 3 colls, 2 par 0.006s 0.001s 0.0005s 0.0005s\n", + "\n", + " Parallel GC work balance: 27.29% (serial 0%, perfect 100%)\n", + "\n", + " TASKS: 26 (1 bound, 25 peak workers (25 total), using -N12)\n", + "\n", + " SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)\n", + "\n", + " INIT time 0.004s ( 0.002s elapsed)\n", + " MUT time 0.095s ( 0.092s elapsed)\n", + " GC time 0.017s ( 0.008s elapsed)\n", + " RP time 0.000s ( 0.000s elapsed)\n", + " PROF time 0.000s ( 0.000s elapsed)\n", + " EXIT time 0.002s ( 0.001s elapsed)\n", + " Total time 0.118s ( 0.103s elapsed)\n", + "\n", + " Alloc rate 1,068,522,257 bytes per MUT second\n", + "\n", + " Productivity 80.4% of total user, 88.9% of total elapsed\n", + "\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent19) --enable-profiling (configuration changed)\n", + "Configuring executable 'advent19' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent19' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent19' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent19/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent19/build/advent19/advent19-tmp/Main.dyn_o ) [Control.Parallel.Strategies changed]\n", + "\n", + "\u001b[;1madvent19/Main.hs:3:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Debug.Trace’ is redundant\n", + " except perhaps to import instances from ‘Debug.Trace’\n", + " To import instances alone, use: import Debug.Trace()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m3 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Debug.Trace\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:19:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Data.Ord’ is redundant\n", + " except perhaps to import instances from ‘Data.Ord’\n", + " To import instances alone, use: import Data.Ord()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m19 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Data.Ord\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:56:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘benefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m56 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:166:22: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘prevBenefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m166 |\u001b[0m\u001b[0m makeAgendum previous \u001b[;1m\u001b[35mprevBenefit\u001b[0m\u001b[0m newState = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:193:24: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘robots’ shadows the existing binding\n", + " defined at advent19/Main.hs:45:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m193 |\u001b[0m\u001b[0m where blueprintify n \u001b[;1m\u001b[35mrobots\u001b[0m\u001b[0m = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^\u001b[0m\u001b[0m\n", + "[1 of 2] Compiling AoC ( src/AoC.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent19/build/advent19/advent19-tmp/AoC.p_o )\n", + "[2 of 2] Compiling Main ( advent19/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent19/build/advent19/advent19-tmp/Main.p_o )\n", + "\n", + "\u001b[;1madvent19/Main.hs:3:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Debug.Trace’ is redundant\n", + " except perhaps to import instances from ‘Debug.Trace’\n", + " To import instances alone, use: import Debug.Trace()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m3 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Debug.Trace\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:19:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-imports\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " The import of ‘Data.Ord’ is redundant\n", + " except perhaps to import instances from ‘Data.Ord’\n", + " To import instances alone, use: import Data.Ord()\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m19 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mimport Data.Ord\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:56:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘benefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m56 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:166:22: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-matches\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘prevBenefit’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m166 |\u001b[0m\u001b[0m makeAgendum previous \u001b[;1m\u001b[35mprevBenefit\u001b[0m\u001b[0m newState = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent19/Main.hs:193:24: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wname-shadowing\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " This binding for ‘robots’ shadows the existing binding\n", + " defined at advent19/Main.hs:45:1\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m193 |\u001b[0m\u001b[0m where blueprintify n \u001b[;1m\u001b[35mrobots\u001b[0m\u001b[0m = \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent19/build/advent19/advent19 ...\n", + "1199\n" + ] + } + ], + "source": [ + "! cd .. && for i in {01..25}; do cabal run advent${i} --enable-profiling -- +RTS -N -pj -s -hT ; done" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rm: cannot remove '../times.csv': No such file or directory\n", + "rm: cannot remove '../times_raw.csv': No such file or directory\n" + ] + } + ], + "source": [ + "! rm ../times.csv\n", + "! rm ../times_raw.csv" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "Collapsed": "false", + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Up to date\n", + "66719\n", + "198551\n", + "Up to date\n", + "13009\n", + "10398\n", + "Up to date\n", + "7727\n", + "2609\n", + "Up to date\n", + "513\n", + "878\n", + "Up to date\n", + "TGWSMRBPN\n", + "TZLTLWRNF\n", + "Up to date\n", + "1080\n", + "3645\n", + "Up to date\n", + "1084134\n", + "6183184\n", + "Up to date\n", + "1823\n", + "211680\n", + "Up to date\n", + "6243\n", + "2630\n", + "Up to date\n", + "15140\n", + "███ ███ ██ ██ ████ ██ ██ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ █ █ █ █ █ █ █ █ █ █ \n", + "█ █ ███ █ ████ █ █ ██ ████ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ ██ █ █ ████ ███ █ █ █ \n", + " \n", + "\n", + "Up to date\n", + "112815\n", + "25738411485\n", + "Up to date\n", + "468\n", + "459\n", + "Up to date\n", + "5675\n", + "20383\n", + "Up to date\n", + "644\n", + "27324\n", + "Up to date\n", + "5147333\n", + "13734006908372\n", + "Up to date\n", + "1792\n", + "2587\n", + "Up to date\n", + "3211\n", + "1589142857183\n", + "Up to date\n", + "3364\n", + "2006\n", + "Up to date\n", + "1199\n", + "3510\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent20) (file advent20/Main.hs changed)\n", + "Preprocessing executable 'advent20' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent20' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent20/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent20/build/advent20/advent20-tmp/Main.o, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent20/build/advent20/advent20-tmp/Main.dyn_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent20/build/advent20/advent20 ...\n", + "8721\n", + "831878881825\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent21) (file advent21/Main.hs changed)\n", + "Preprocessing executable 'advent21' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent21' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent21/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent21/build/advent21/advent21-tmp/Main.o, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent21/build/advent21/advent21-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent21/Main.hs:38:9: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-uni-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In a pattern binding:\n", + " Patterns of type ‘Shout’ not matched: Literal _\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m38 |\u001b[0m\u001b[0m where \u001b[;1m\u001b[35m(Operation _ rootL rootR) = monkeys ! \"root\"\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent21/Main.hs:50:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wincomplete-patterns\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Pattern match(es) are non-exhaustive\n", + " In an equation for ‘binarySearch’:\n", + " Patterns of type ‘Monkeys’, ‘Monkeys’, ‘Int’, ‘Int’ not matched:\n", + " (Data.Map.Internal.Bin _ _ _ _ _) (Data.Map.Internal.Bin _ _ _ _ _)\n", + " _ _\n", + " (Data.Map.Internal.Bin _ _ _ _ _) Data.Map.Internal.Tip _ _\n", + " Data.Map.Internal.Tip (Data.Map.Internal.Bin _ _ _ _ _) _ _\n", + " Data.Map.Internal.Tip Data.Map.Internal.Tip _ _\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m50 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mbinarySearch values operations lower upper \u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent21/build/advent21/advent21 ...\n", + "21120928600114\n", + "3453748220116\n", + "Up to date\n", + "26558\n", + "110400\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent23) (file advent23/Main.hs changed)\n", + "Preprocessing executable 'advent23' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent23' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent23/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent23/build/advent23/advent23-tmp/Main.o, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent23/build/advent23/advent23-tmp/Main.dyn_o )\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent23/build/advent23/advent23 ...\n", + "4236\n", + "1023\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent24) (file advent24/Main.hs changed)\n", + "Preprocessing executable 'advent24' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent24' for advent-of-code22-0.1.0.0..\n", + "[2 of 2] Compiling Main ( advent24/Main.hs, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent24/build/advent24/advent24-tmp/Main.o, /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent24/build/advent24/advent24-tmp/Main.dyn_o )\n", + "\n", + "\u001b[;1madvent24/Main.hs:53:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘cost’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m53 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mmakeLenses ''Agendum\u001b[0m\u001b[0m \n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^^^^^^^^^^^^^\u001b[0m\u001b[0m\n", + "\n", + "\u001b[;1madvent24/Main.hs:221:1: \u001b[;1m\u001b[35mwarning:\u001b[0m\u001b[0m\u001b[;1m [\u001b[;1m\u001b[35m-Wunused-top-binds\u001b[0m\u001b[0m\u001b[;1m]\u001b[0m\u001b[0m\u001b[;1m\n", + " Defined but not used: ‘showSafe’\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\n", + "\u001b[;1m\u001b[34m221 |\u001b[0m\u001b[0m \u001b[;1m\u001b[35mshowSafe\u001b[0m\u001b[0m valley = unlines $ reverse rows\n", + "\u001b[;1m\u001b[34m |\u001b[0m\u001b[0m\u001b[;1m\u001b[35m ^^^^^^^^\u001b[0m\u001b[0m\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent24/build/advent24/advent24 ...\n", + "288\n", + "861\n", + "Build profile: -w ghc-9.2.5 -O1\n", + "In order, the following will be built (use -v for more details):\n", + " - advent-of-code22-0.1.0.0 (exe:advent25) (configuration changed)\n", + "Configuring executable 'advent25' for advent-of-code22-0.1.0.0..\n", + "Preprocessing executable 'advent25' for advent-of-code22-0.1.0.0..\n", + "Building executable 'advent25' for advent-of-code22-0.1.0.0..\n", + "Linking /home/neil/Programming/advent-of-code-22/dist-newstyle/build/x86_64-linux/ghc-9.2.5/advent-of-code22-0.1.0.0/x/advent25/build/advent25/advent25 ...\n", + "20==1==12=0111=2--20\n" + ] + } + ], + "source": [ + "! cd .. && for i in {01..25}; do /usr/bin/time -f \"%C,%S,%E,%M\" -o times.csv -a cabal run advent${i}; done" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "Collapsed": "false", + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "66719\n", + "198551\n", + "13009\n", + "10398\n", + "7727\n", + "2609\n", + "513\n", + "878\n", + "TGWSMRBPN\n", + "TZLTLWRNF\n", + "1080\n", + "3645\n", + "1084134\n", + "6183184\n", + "1823\n", + "211680\n", + "6243\n", + "2630\n", + "15140\n", + "███ ███ ██ ██ ████ ██ ██ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ █ █ █ █ █ █ █ █ █ █ \n", + "█ █ ███ █ ████ █ █ ██ ████ ███ \n", + "█ █ █ █ █ █ █ █ █ █ █ █ █ \n", + "███ █ ██ █ █ ████ ███ █ █ █ \n", + " \n", + "\n", + "112815\n", + "25738411485\n", + "468\n", + "459\n", + "5675\n", + "20383\n", + "644\n", + "27324\n", + "5147333\n", + "13734006908372\n", + "1792\n", + "2587\n", + "3211\n", + "1589142857183\n", + "3364\n", + "2006\n", + "1199\n", + "3510\n", + "8721\n", + "831878881825\n", + "21120928600114\n", + "3453748220116\n", + "26558\n", + "110400\n", + "4236\n", + "1023\n", + "288\n", + "861\n", + "20==1==12=0111=2--20\n" + ] + } + ], + "source": [ + "! cd .. && for i in {01..25}; do /usr/bin/time -f \"%C,%S,%E,%M\" -o times_raw.csv -a advent${i}; done" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "!mv ../*prof ." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "!mv ../times.csv ." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "!mv ../times_raw.csv ." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "!mv ../*hp ." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/bin/bash: -c: line 1: syntax error near unexpected token `;'\n", + "/bin/bash: -c: line 1: ` for f in *hp ; do hp2ps $<_io.TextIOWrapper name='advent24.prof' mode='r' encoding='UTF-8'> ; done'\n" + ] + } + ], + "source": [ + "! for f in *hp ; do hp2ps ${f} ; done" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['advent13.prof',\n", + " 'advent10.prof',\n", + " 'advent03.prof',\n", + " 'advent07.prof',\n", + " 'advent20.prof',\n", + " 'advent19.prof',\n", + " 'advent01.prof',\n", + " 'advent18.prof',\n", + " 'advent06.prof',\n", + " 'advent09.prof',\n", + " 'advent08.prof',\n", + " 'advent23.prof',\n", + " 'advent21.prof',\n", + " 'advent22.prof',\n", + " 'advent16.prof',\n", + " 'advent25.prof',\n", + " 'advent11.prof',\n", + " 'advent02.prof',\n", + " 'advent15.prof',\n", + " 'advent17.prof',\n", + " 'advent05.prof',\n", + " 'advent12.prof',\n", + " 'advent04.prof',\n", + " 'advent14.prof',\n", + " 'advent24.prof']" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "glob.glob('*prof')" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "Collapsed": "false", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'program': 'advent13',\n", + " 'total_time': 0.08,\n", + " 'total_alloc': 10281760,\n", + " 'total_ticks': 264,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent10',\n", + " 'total_time': 0.01,\n", + " 'total_alloc': 631808,\n", + " 'total_ticks': 48,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent03',\n", + " 'total_time': 0.04,\n", + " 'total_alloc': 6018112,\n", + " 'total_ticks': 120,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent07',\n", + " 'total_time': 0.03,\n", + " 'total_alloc': 3049136,\n", + " 'total_ticks': 108,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent20',\n", + " 'total_time': 116.93,\n", + " 'total_alloc': 55860434768,\n", + " 'total_ticks': 398748,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent19',\n", + " 'total_time': 125807.27,\n", + " 'total_alloc': 1964531122296,\n", + " 'total_ticks': 429011004,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent01',\n", + " 'total_time': 0.06,\n", + " 'total_alloc': 11516576,\n", + " 'total_ticks': 192,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent18',\n", + " 'total_time': 0.36,\n", + " 'total_alloc': 68244096,\n", + " 'total_ticks': 1224,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent06',\n", + " 'total_time': 0.02,\n", + " 'total_alloc': 5025888,\n", + " 'total_ticks': 84,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent09',\n", + " 'total_time': 0.37,\n", + " 'total_alloc': 39708256,\n", + " 'total_ticks': 1248,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent08',\n", + " 'total_time': 0.69,\n", + " 'total_alloc': 214597512,\n", + " 'total_ticks': 2352,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent23',\n", + " 'total_time': 1977.02,\n", + " 'total_alloc': 26387446504,\n", + " 'total_ticks': 6741780,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent21',\n", + " 'total_time': 1.97,\n", + " 'total_alloc': 351135824,\n", + " 'total_ticks': 6720,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent22',\n", + " 'total_time': 3671.94,\n", + " 'total_alloc': 528445105288,\n", + " 'total_ticks': 12521556,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent16',\n", + " 'total_time': 910.42,\n", + " 'total_alloc': 296137053800,\n", + " 'total_ticks': 3104592,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent25',\n", + " 'total_time': 0.01,\n", + " 'total_alloc': 642496,\n", + " 'total_ticks': 48,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent11',\n", + " 'total_time': 3.02,\n", + " 'total_alloc': 655812832,\n", + " 'total_ticks': 10308,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent02',\n", + " 'total_time': 0.06,\n", + " 'total_alloc': 9613016,\n", + " 'total_ticks': 192,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent15',\n", + " 'total_time': 23014.42,\n", + " 'total_alloc': 126607950592,\n", + " 'total_ticks': 78480684,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent17',\n", + " 'total_time': 198.34,\n", + " 'total_alloc': 77649009464,\n", + " 'total_ticks': 676368,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent05',\n", + " 'total_time': 0.02,\n", + " 'total_alloc': 3396888,\n", + " 'total_ticks': 84,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent12',\n", + " 'total_time': 7.58,\n", + " 'total_alloc': 1598902400,\n", + " 'total_ticks': 25836,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent04',\n", + " 'total_time': 0.03,\n", + " 'total_alloc': 2913824,\n", + " 'total_ticks': 96,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent14',\n", + " 'total_time': 5.8,\n", + " 'total_alloc': 258169680,\n", + " 'total_ticks': 19788,\n", + " 'initial_capabilities': 12},\n", + " {'program': 'advent24',\n", + " 'total_time': 18.13,\n", + " 'total_alloc': 3268072336,\n", + " 'total_ticks': 61836,\n", + " 'initial_capabilities': 12}]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "profs = []\n", + "for fn in glob.glob('*prof'):\n", + " with open(fn) as f:\n", + " j = json.load(f)\n", + " prof = {}\n", + " for n in 'program total_time total_alloc total_ticks initial_capabilities'.split():\n", + " prof[n] = j[n]\n", + " profs.append(prof)\n", + "profs" + ] + }, + { + "cell_type": "code", + "execution_count": 158, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
total_timetotal_alloctotal_ticksinitial_capabilities
program
advent010.061151657619212
advent020.06961301619212
advent030.04601811212012
advent040.0329138249612
advent050.0233968888412
advent060.0250258888412
advent070.03304913610812
advent080.69214597512235212
advent090.3739708256124812
advent100.016318084812
advent113.026558128321030812
advent127.5815989024002583612
advent130.081028176026412
advent145.802581696801978812
advent1523014.421266079505927848068412
advent16910.42296137053800310459212
advent17198.347764900946467636812
advent180.3668244096122412
advent19125807.27196453112229642901100412
advent20116.935586043476839874812
advent211.97351135824672012
advent223671.945284451052881252155612
advent231977.0226387446504674178012
advent2418.1332680723366183612
advent250.016424964812
\n", + "
" + ], + "text/plain": [ + " total_time total_alloc total_ticks initial_capabilities\n", + "program \n", + "advent01 0.06 11516576 192 12\n", + "advent02 0.06 9613016 192 12\n", + "advent03 0.04 6018112 120 12\n", + "advent04 0.03 2913824 96 12\n", + "advent05 0.02 3396888 84 12\n", + "advent06 0.02 5025888 84 12\n", + "advent07 0.03 3049136 108 12\n", + "advent08 0.69 214597512 2352 12\n", + "advent09 0.37 39708256 1248 12\n", + "advent10 0.01 631808 48 12\n", + "advent11 3.02 655812832 10308 12\n", + "advent12 7.58 1598902400 25836 12\n", + "advent13 0.08 10281760 264 12\n", + "advent14 5.80 258169680 19788 12\n", + "advent15 23014.42 126607950592 78480684 12\n", + "advent16 910.42 296137053800 3104592 12\n", + "advent17 198.34 77649009464 676368 12\n", + "advent18 0.36 68244096 1224 12\n", + "advent19 125807.27 1964531122296 429011004 12\n", + "advent20 116.93 55860434768 398748 12\n", + "advent21 1.97 351135824 6720 12\n", + "advent22 3671.94 528445105288 12521556 12\n", + "advent23 1977.02 26387446504 6741780 12\n", + "advent24 18.13 3268072336 61836 12\n", + "advent25 0.01 642496 48 12" + ] + }, + "execution_count": 158, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "performance = pd.DataFrame(profs).set_index('program').sort_index()\n", + "performance" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWoAAAE3CAYAAACDyAvKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAVwElEQVR4nO3debBkdXnG8e/rzCAKgujcxAVljFHBUAqKGKORqKgE3BKjcRIxGiwqZZmYlFUuiQvRxBBTKi6RFDEUGjckbohLQAGNGzAMKOCoWAEVNHJdEFBBgTd/nHOHnqH73r493b/7Xub7qeqa3n79PhzbZ850n+6OzESSVNftVjqAJGlxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFTezoo6IEyPiqoi4eIz73jsizoqICyLiqxFx+KxySdJqM8s96pOAw8a87yuAD2TmgcCzgLfPKpQkrTYzK+rM/Bzw48HrIuK+EfGpiDg/Iv4nIvZduDuwR39+T+B7s8olSavN2sbzTgD+IjMvjYiH0+05PxY4Bjg9Iv4S2A04tHEuSSqrWVFHxO7A7wCnRMTC1bfv/9wInJSZb4iIRwD/GRH7Z+bNrfJJUlUt96hvB1ydmQcMue0o+tezM/NLEbErsB64ql08Saqp2eF5mXkNcFlEPAMgOg/ub/4O8Lj++v2AXYH5VtkkqbKY1bfnRcT7gN+j2zP+AfBq4EzgeODuwDrg/Zn5moh4IPDvwO50byy+JDNPn0kwSVplZlbUkqTp8JOJklScRS1Jxc3kqI/169fnhg0bZvHQknSbdP755/8wM+eG3TaTot6wYQObNm2axUNL0m1SRHx71G2+9CFJxVnUklScRS1JxVnUklScRS1JxVnUklScRS1JxVnUklRc6194kbTKbHjZx0fedvmxRzRMsvNyj1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJam4sYs6ItZExAURcdosA0mStrWcPeoXAVtmFUSSNNxYRR0RewNHAO+YbRxJ0vbG3aM+DngJcPOoO0TE0RGxKSI2zc/PTyObJIkxijoingRclZnnL3a/zDwhMw/KzIPm5uamFlCSdnbj7FE/EnhKRFwOvB94bES8e6apJElbLVnUmfnyzNw7MzcAzwLOzMxnzzyZJAnwOGpJKm9ZP8WVmWcDZ88kiSRpKPeoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJak4i1qSirOoJam4JYs6InaNiHMj4isRcUlE/H2LYJKkztox7nMD8NjMvC4i1gGfj4hPZuaXZ5xNksQYRZ2ZCVzXX1zXn3KWoSRJtxjrNeqIWBMRFwJXAWdk5jlD7nN0RGyKiE3z8/NTjilJO6+xijozb8rMA4C9gYMjYv8h9zkhMw/KzIPm5uamHFOSdl7LOuojM68GzgYOm0UYSdKtjXPUx1xE3Lk/fwfgUODrM84lSeqNc9TH3YF3RsQaumL/QGaeNttYkqQF4xz18VXgwAZZJElD+MlESSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSrOopak4ixqSSpuyaKOiHtFxFkRsSUiLomIF7UIJknqrB3jPjcCL87MzRFxJ+D8iDgjM78242ySJMbYo87M72fm5v78tcAW4J6zDiZJ6izrNeqI2AAcCJwzkzSSpFsZu6gjYnfgg8BfZ+Y1Q24/OiI2RcSm+fn5aWaUpJ3aWEUdEevoSvo9mfmhYffJzBMy86DMPGhubm6aGSVppzbOUR8B/AewJTPfOPtIkqRB4+xRPxI4EnhsRFzYnw6fcS5JUm/Jw/My8/NANMgiSRrCTyZKUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnEWtSQVZ1FLUnFLFnVEnBgRV0XExS0CSZK2Nc4e9UnAYTPOIUkaYcmizszPAT9ukEWSNISvUUtScVMr6og4OiI2RcSm+fn5aT2sJO30plbUmXlCZh6UmQfNzc1N62ElaafnSx+SVNw4h+e9D/gS8ICIuCIijpp9LEnSgrVL3SEzN7YIIkkazpc+JKk4i1qSirOoJak4i1qSirOoJam4JY/6kDSeDS/7+MjbLj/2iIZJdFvjHrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFWdRS1JxFrUkFbd2pQNI0o7Y8LKPj7zt8mOPaJhkdtyjlqTiLGpJKm6slz4i4jDgzcAa4B2ZeexMU0nSjI16yaTiyyVL7lFHxBrgX4HfBx4IbIyIB846mCSpM84e9cHAtzLzfwEi4v3AU4GvzTKYtLNYTXt2WhmRmYvfIeKPgMMy8/n95SOBh2fmC7e739HA0f3FBwDfGPJw64EfTpBzknWt1txWZ1XP13JW9XwtZ1XP13LWtPPtk5lzQ1dk5qIn4Bl0r0svXD4SeOtS60Y81qZW61qtua3Oqp7PbeG2WOlZLfONc9THFcC9Bi7vDXxvjHWSpCkYp6jPA+4XEfeJiF2AZwGnzjaWJGnBkm8mZuaNEfFC4L/pDs87MTMvmXDeCQ3XtVpzW51VPV/LWdXztZxVPV/LWc3yLflmoiRpZfnJREkqzqKWpOIsakkqzqKWpOJWpKgj4lWL3PbEiDgqIjZsd/2fL7ImIuKZEfGM/vzjIuItEfGCiBj7vzEizlzi9vXbXX52P+foiIhF1v1BRNylPz8XEe+KiIsi4uSI2HvEmjdGxCPHzT6w7i4R8aqIeH6/Lf4uIk6LiH+JiL0WWfeYiHhbRHw0Ij4YEcdGxG8uMeuJEXF8RJzarzu+/wKvifi88Hkx4vF2qufF0MdaiaM+IuI7mXnvIde/DngUsBl4MnBcZr61v21zZj5kxOO9Hfg1YBfgGuD2wMeAw4EfZOaLhqz56vZXAfen/+h7Zj5oyJqtGSLiFcDvAu8FngRckZl/MyLf1zLzgf35k4EvA6cAhwJ/mpmPH7JmHvg2MAecDLwvMy8Y9vjbrfsEcBGwB7Bff/4DwOOBB2fmU4esORb4deAzwNOAy4BvAi8AXpeZpwxZcxzd9noX3YeioPsw1HOAS4dt8zGy+7zweTEs+071vBhqko9AjvkxyWtGnK4Fbhyx5iJgbX/+zsAngDf1ly9YZNZF/Z/rgB8Bu/SX1y7cNmTNqcC7gX2BfYANwHf78/uMWHPBwPnNwG4Dc4fO6W//xsD587e77cLFZgH3A14JXAJ8HXg1cP9FZl3Y/xnAlWPOumjg/FrgC/35vYCLR6z55ojrg+7/kD4vfF74vJjgeTHsNMuXPq4G7peZe2x3uhPw/RFr1mbmjQCZeTXd35J7RMQpdH/7jbKw5lfAeZn5y/7yjcBNwxZk5lOAD9IdfP7gzLwc+FVmfjszvz1izh0i4sCIeCiwJjN/NjB36Jze2RHxmoi4Q3/+adD9sxL46Yg12T/2pZn52sz8LeCZwK50T8hRbtf/U/ZewO4L/ySMiLsyehvevPBPcOAedB9sIjN/Qvd/sGGuj4iDh1z/MOD6RfJdjc+LBT4vbnE1Pi9GW06rL+cE/ANw8Ijb/nnE9acBh4x4rJsXmfVJYPch198NOHeJnLsBb6T7G/OKJe571nanu/fX35VFvmiF7m/QY4Dv9Keb6fYU3gvce8SaCybc7huBH/SnpwOfBs4ArgSOHrHmj+n+OX16n++I/vo54L0j1jwEOIfu625P709b+use6vPC54XPi8meF8NOpT6Z2O9ZkJm/GHLbPTPzymU+3m50/9y4aoz7Phh4RGb+23Jm9GvXALfPzJ+Pcd896fYEfrTE/XbPzOuWm2UgT2T38f+1wAF0/9wdtWdCv+f0G3TfPX71MmbdDbgn3R7WFZn5f5NkXmKGz4tb7ufz4pYZt/nnxdY1syzq/p3Ng+n+B0u6b907NxcZOsmalrOq52s9a8Rj7ZuZX2+xrvqs6vlmNSsi1mX3T/zB69Zn5qLf3zzJuuqzJs23jeXsfi/nBDwB+BbdPzPe0Z8+1V/3hGmtaTmrer7WsxbJ8J0JnzPLXld9VvV8054FPIbuaI95upc9NgzctnmRx1v2uuqzJs037DTWj9tO6M3Aodm96L5VRNyH7k2P/aa0puWs6vmazYqIt4yYH3TvwA+/cYJ11WdVz9d41uuBJ2bmJdH9OtQZEXFkZn6Z0W9ATrqu+qxJ893KLIt6LbccRznoSro3Uaa1puWs6vlaznoe8GLghiG3bVwk3yTrqs+qnq/lrF2y/xrkzPyviNgCfCgiXkZ/xMoU11WfNWm+W5llUZ8InBfdj+F+t7/uXnQ/PHDiFNe0nFU9X8tZ59EdS/vF7W+IiGMWyTfJuuqzqudrOetXEXG37N887PcmH0d3hMZ9F8k3ybrqsybNdyuzfjNxP7pfLN/67i9wamaO/AXzSda0nFU9X6tZ0R0NcH0u453rSddVn1U9X8tZEXEoMJ+ZX9nu+j2BF2bmP05rXfVZk+YbajkvaE9yAl40znU7uqblrOr53BZui5WeVT3fatgW29x/OXee5MSQdzdZ4qD9Sda0nFU9n9vCbbHSs6rnWw3bYvA0s9eoI2Ij8CfAfSJi8Mdw70T3+fqprGk5q3q+lrOq52s5q3q+lrOq52s5a9J8w8zyzcQv0n1Gfz3whoHrrwW2/yaqHVnTclb1fC1nVc/Xclb1fC1nVc/Xctak+W6l1EfIJUm3NstvzwMgIv4wIi6NiJ9GxDURcW1EXDPtNS1nVc/Xclb1fC1nVc/Xclb1fC1nTZpvG8t5QXuSE93HkPeb9ZqWs6rnc1u4LVZ6VvV8q2FbDJ5mvkdN94sJWxqsaTmrer6Ws6rnazmrer6Ws6rnazlr0nxbzfw16oh4M933vH6EgY+iZuaHprmm5azq+VrOqp6v5azq+VrOqp6v5axJ8w2a5VEfC/YAfk73DW0LElgs5CRrWs6qnq/lrOr5Ws6qnq/lrOr5Ws6aNN9WHvUhScW1OOrj/hHxmYi4uL/8oOh+kXeqa1rOqp6v5azq+VrOqp6v5azq+VrOmjTfNnbkncgx3/H8LN0vh1wwcN3QXzDekTUtZ1XP57ZwW6z0rOr5VsO2GDy1OOrjjpl57nbX3TiDNS1nVc/Xclb1fC1nVc/Xclb1fC1nTZpvqxZF/cOIuC/9F2VH90sHI39McwfWtJxVPV/LWdXztZxVPV/LWdXztZw1ab5bLGf3e5IT3S8Yf5ruXc8rgc8D+0x7TctZ1fO5LdwWKz2rer7VsC0GTy2Oo16TmTdF91Pst8vMa2expuWs6vlazqqer+Ws6vlazqqer+WsSfMNavHSx2URcQLw28B1M1zTclb1fC1nVc/Xclb1fC1nVc/Xctak+W6xnN3vSU7AHYBn0h3cfTnwNuBR017Tclb1fG4Lt8VKz6qebzVsi20eYzl33tETsBfwLuCmWa5pOat6PreF22KlZ1XPtxq2RYuXPoiIQyLi7cBmYFe6v12mvqblrOr5Ws6qnq/lrOr5Ws6qnq/lrEnzbbWcVp/kBFwGfBjYCOw2qzUtZ1XP57ZwW6z0rOr5VsO2GDy1OOpjj8xc1pdkT7Km5azq+VrOqp6v5azq+VrOqp6v5axJ823zGLMq6oh4K/0B3sNk5l9NY03LWdXztZxVPV/LWdXztZxVPV/LWZPmG2aWr1FvAs6nez3mIcCl/ekA4KYprmk5q3q+lrOq52s5q3q+lrOq52s5a9J8tzbJ6yXLOQFnAesGLq8Dzpr2mpazqudzW7gtVnpW9XyrYVsMnloc9XEP4E4Dl3fvr5v2mpazqudrOat6vpazqudrOat6vpazJs23VYtfeDkWuCAizuovHwIcM4M1LWdVz9dyVvV8LWdVz9dyVvV8LWdNmm+rJr/wEhH3AI4EtgB3BL6XmZ+b9pqWs6rnazmrer6Ws6rnazmrer6WsybNt9VyXieZ5AQ8H7gI+AndazW/AM6c9pqWs6rnc1u4LVZ6VvV8q2FbbPMYy7nzJKc+4K7Ahf3lfYGTp72m5azq+dwWbouVnlU932rYFoOnFm8mXp+Z1wNExO0z8+vAA2awpuWs6vlazqqer+Ws6vlazqqer+WsSfNt1eLNxCsi4s7AR4AzIuInwPdmsKblrOr5Ws6qnq/lrOr5Ws6qnq/lrEnzbdXkzcStwyIOAfYEPpWZv5zVmpazqudrOat6vpazqudrOat6vpazJs7XsqglScvX5GtOJUmTs6glqTiLWpKKs6i16kXEmh1c3+LoJ2livpmo0iJiA/Ap4BzgQOCbwHOArwEnAk+g+7HQAP62//PjmfnSfv1RwEvpDoe6FLghM18YEScBP+4fczNwMnAc3Q+R/gJ4XmZ+IyKeCzwNWAPsD7wB2IXu48A3AIdn5o9ntwWkNsdRSzvqAcBRmfmFiDgReEF//fWZ+aj+exS+DDyU7mO6p0fE04BzgVfSfRfwtcCZwFcGHvf+wKGZeVNE7AE8OjNvjIhDgdcBT+/vtz9doe8KfAt4aWYeGBFvovtL47gZ/XdLgEWt1eG7mfmF/vy7gYVfxji5//NhwNmZOQ8QEe8BHt3f9tmFPd6IOIWunBeckpkLX+C+J/DOiLgf3a9yrBu431mZeS1wbUT8FPhYf/1FwIOm8R8oLcbXqLUabP/63MLln/V/xoh1o65f8LOB86+lK+T9gSfT7T0vuGHg/M0Dl2/GnR01YFFrNbh3RDyiP78R+Px2t58DHBIR6/s3FjcCn6V76eOQiNirf8Pw6Yy2J3Blf/65U0suTYFFrdVgC/BnEfFV4C7A8YM3Zub3gZfTfYXkV4DNmfnRzLyS7rXmc4BP070B+dMRM14P/FNEfIHujUOpDI/6UGn9UR+n9S9JTLJ+98y8rt+j/jBwYmZ+eJoZpVlzj1q3dcdExIXAxcBldN9gJq0q7lFLUnHuUUtScRa1JBVnUUtScRa1JBVnUUtScRa1JBX3/4O+JdWqoFOMAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.total_ticks.plot.bar()" + ] + }, + { + "cell_type": "code", + "execution_count": 160, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 160, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.total_ticks.plot.bar(logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 161, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 161, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.total_alloc.plot.bar()" + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 162, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.total_alloc.plot.bar(logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 163, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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nXfemS233LLdpUjSmFfaIYOenh623XZbdt11V6qu5a5RIjNZt24dPT09TJkypd3lSNKY19ZDHjJzSWbO7erq2uy5l156iUmTJtkYGKUigkmTJtkDJGms6oqIhcUP41Io7ZABYGNglHP/ShrDejNzbruLqFbaIQNJktQ6bW0QFCdjWNLd3X3yUK/ddf71Td32mgXvG/T5Z555hssuu4xTTjll4Iw1a7j99ts54YQTBt/WmjUcfvjhrFy5st/nV6xYwdq1a/nzP/9zAK699lruu+8+5s+fP6w8SZLqVarTJpbJM888w1e/+tVBX7NmzRouu+yyhre1YsUKli5duunxkUceOWBjQJKkkdDWBkFEHBERC3t7e9tZRr/mz5/PL3/5S2bOnMmpp57KqaeeyrRp09h7771ZvHjxptfccsstzJw5k3PPPZc1a9bwrne9i3333Zd9992X22+/fcjtvPzyy5x++uksXryYmTNnsnjxYhYtWsS8efMAeOyxxzjmmGOYMWMGM2bM2CzzoYceYp999mH58uXce++9zJo1i5kzZzJ9+nQefPDB5n8wkqRRqWOGDFptwYIFrFy5khUrVnDVVVdxwQUXcPfdd/Pkk0/y9re/nQMOOIAFCxZwzjnncN111wHw4osvcuONNzJhwgQefPBB5syZw5133jnodsaPH8/nPvc57rzzTs477zwAFi1atOn5T3ziE8yePZurr76a3t5enn/+eZ5++mkA7r//fo4//ni+9rWvMXPmTD7+8Y/zyU9+kr/6q7/i5ZdfpowNLUlSOZX6KIOyuPXWW5kzZw5dXV3ssMMOzJ49m+XLl7Pddtu95nWvvPIK8+bNY8WKFXR1dfHAAw80vO2bbrqJSy+9FICuri4mTpzI008/zRNPPMFRRx3FVVddxdve9jYA/viP/5jPf/7z9PT08P73v5/dd9+94e1LksYGGwQ1qPX0zueeey477LADd999N6+++ioTJkwYsZomTpzILrvswm233bapQXDCCSew//77c/3113PIIYdw4YUX8u53v3vEapA0cvpOpF4zoZ/Jy2eub1E1GgFdZbvaoXMIBrDtttvy3HPPAXDAAQewePFient7eeKJJ1i2bBmzZs16zWsA1q9fz0477cQWW2zB17/+9Zq77PvmVPuzP/szzj//fAB6e3t59tlngcpQwzXXXMOll166aWLjQw89xG677cYnPvEJjjzySH7+858P+/1LkkZUb2bOLUtjADpoDsFQhwk226RJk3jnO9/JtGnTOOyww5g+fTozZswgIjj77LPZcccdmTRpEuPGjWPGjBmceOKJnHLKKRx77LFceeWVHHTQQXR313bdioMOOogFCxYwc+ZMPv3pT7/muS9+8YvMnTuXiy66iK6uLs4//3x22mknALq7u7nuuut4z3veQ3d3N/fddx/f+MY32HLLLdlxxx05/fTTm/65SJJGp9Je7XDVqlXstddebapIreJ+lvrnkMHoVsarHXoeAkmS5KTCVrrhhhs47bTTXrNsypQpXH311W2qSJKkChsELXTIIYdwyCGHtLsMSZI248WNJElSe+cQZOaSzJzb1dXVzjIkSRrznFQoSVKHi4jdIuKiiPh21bKjI+JfI+LfIuK9Q2XYIJAkqYQi4uKIeDwiVvZZfmhE3B8RqyNiPkBmPpSZJ1W/LjOvycyTgROBvxxqe53TIDhzYnNvQ6jl8sdQ+yWQ16xZw7Rp02p6qwOtd/PNN3P44YfXndGf4447joceeqjf5z760Y9y3333Dbr+iSeeyLe//e3Nlvf9PO655x5OPPHEhmqVpDFqEXBo9YKI6AK+AhwGTAXmRMTUIXI+W6wzqM5pELRYsxsEZXLvvffS29vLbrvtttlzvb29XHjhhUydOtT3q399P4+9996bnp4efv3rXw+7XkkaizJzGfBUn8WzgNVFj8DLwOXAUf2tHxX/BHw3M+8aans2CAYwf/58fvnLXzJz5kxOPfVUMpNTTz2VadOmsffee7N48eJNr7vllluYOXMm5557LmvWrOFd73oX++67L/vuuy+33357Tdurd72nnnqKo48+munTp/OOd7xj03ULnn/+eT784Q+z9957M336dK666qrN1v3mN7/JUUf97vuzzTbbcPrpp7P//vtzxx13cOCBB266bPNFF13EHnvswYEHHsjJJ5/MvHnzNq23bNky/uRP/oTddtttU29B388D4IgjjuDyyy+v6XOQpDFiXETcWXWbW+N6k4GHqx73AJMjYlJEXADsExEbz4H/ceBg4LiI+NiQBdVTfbOV+bDDBQsWsHLlSlasWAHAVVddxYoVK7j77rt58sknefvb384BBxzAggULOOecc7juuusAePHFF7nxxhuZMGECDz74IHPmzNn0x3Uw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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance[['total_ticks', 'total_alloc']].plot.bar(\n", + " logy=True, secondary_y=['total_alloc'], \n", + " figsize=(8, 6), title=\"Internal time and memory\")\n", + "plt.savefig('internal_time_and_memory_log.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 164, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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5MnMnj2bWbNmccoppwDw+OOPc9RRRzFp0iQmTZq0XuaSJUvYddddWbBgAXfffTdTp05l8uTJTJw4kQcffHDg3xhJUsOVV8J/H7g3M7/ZxWzzgA9FYQ9gRWY+BiwAxkfEuIgYBhxbztulQTss32wzZszgrrvuYtGiRcyZM4fzzz+f22+/nT//+c+89a1vZa+99mLGjBl84xvf4IorrgDghRde4Oqrr2b48OE8+OCDTJ8+nYULF3a7nmHDhnHWWWexcOFCzjnnHABmzZq1dvonP/lJpk2bxty5c1m9ejXPPfccTz/9NAD3338/xx57LD/4wQ+YPHkyn/jEJ/jUpz7F+9//fl5++WVWr17dmDdHktRoewIfBO6MiEXluC8A2wNk5vnAfIqvwS2m+CrcCeW0VRFxCnAlxVfhLsjMu7tb2UbT3GvdcMMNTJ8+nba2NrbaaiumTZvGggUL2HTTTdeZ769//SunnHIKixYtoq2tjQceeKDf677mmmu46KKLAGhra2PMmDE8/fTTPPnkkxxxxBHMmTOHt7zlLQC87W1v4ytf+Qrt7e285z3vYfz48f1evySp+TLzBjo/d147TwIf72LafIrmX5eN5rB8reL969nZZ5/NVlttxe23387ChQt5+eWXG1bTmDFj2G677bjxxhvXjjvuuOOYN28eI0aM4MADD+Saa65p2PolSdWx0ey5jx49mmeffRaAvfbai3//93/nwx/+ME899RTXX389X//613n00UfXzgOwYsUKxo4dyyabbMKFF15Y92Hx2nV19K53vYvzzjuPT3/606xevXrtrXGHDRvG5ZdfzoEHHsioUaM47rjjWLJkCTvuuCOf/OQnWbJkCXfccQf77rtvP98JSc3W2beDlg7v8K2cM1c0qRptDAatuff01bWBtvnmm7PnnnsyYcIEDj74YCZOnMikSZOICL72ta+x9dZbs/nmmzNkyBAmTZrE8ccfz8knn8zRRx/NZZddxj777MPIkSPrWtc+++zDjBkzmDx5Mp///OfXmfbtb3+bk046ie9///u0tbVx3nnnsc022wAwcuRIrrjiCvbff39GjhzJPffcw49+9COGDh3K1ltvzemnnz7g74skqXqi3kPUvTFy5Mhcs0e6xr333stOO+004OtS63AbS51zz736IuKFzKxvD7AJNspz7pIkVdlGc869Ea688ko+97nPrTNu3LhxzJ07d5AqkiTJ5t4vBx54IAceeOBglyFJ0jo8LC9JUsXY3CVJqhibuyRJFWNzlySpYgavuZ85ZmAfPajnlq9Q/21fly5dyoQJE+p6qV0td91113HYYYf1OqMzxxxzDEuWLOl02oknnsg999zT7fLHH388P/3pT9cb3/H9uPPOOzn++OP7VaskqbE2mj33gW7ureTuu+9m9erV7LjjjutNW716Nd/73vfYeeed+5Td8f3YZZddaG9v5+GHH+5zvZKkxtpomnvH+7lnZsPu6Q70ermnnnqKI488kokTJ7LHHntwxx13APDcc89xwgknsMsuuzBx4kTmzJmz3rIXX3wxRxxxxNrhUaNGcfrpp7P77rtz8803s/fee6+9Ve33v/993vSmN7H33nvzsY99bO195gGuv/563v72t7Pjjjuu3Yvv+H4AvPvd7+bSSy+t632QJDXfRvM999r7uQPMmTOHRYsWNeSe7gBbbrllr5Y744wz2HXXXbn88su55ppr+NCHPsSiRYv48pe/zJgxY7jzzjsB1t77vdaNN97I9OnT1w4///zzTJgwgbPOOmud+ZYtW8aXv/xlbrvtNkaPHs2+++7LpEmT1k5/7LHHuOGGG7jvvvs4/PDDOeaYY9Z7PwCmTJnCjBkz+OxnP9vj+yBJar6Nprl31Oh7uvd2uRtuuGHtXvm+++7L8uXLWbFiBb/+9a/X2UvebLPN1lv2scce43Wve93a4ba2No4++uj15vv973/PtGnTeO1rXwvAe9/73nXqOvLII9lkk03Yeeedefzxx7usdcstt2TZsmXdvh5J0uDZaJt7X+7p/sorrzB8+PCGLNdZPRFBZhIR3S47YsQIVq5cuXZ4+PDhtLW11bWOWq961avqmnflypWMGDGi2yxJ0uDZaM65d7zH+l577cXs2bNZvXo1Tz75JNdffz1Tp05db74VK1awzTbbsMkmm/DDH/6w7nu693a5vfbai4svvhgorqLfYost2HTTTTnggAM455xz1s7X2WH5nXbaicWLF/dY09SpU/nNb37D008/zapVqzo9f99RZ/emf+CBB/r0TQFJUnPUveceEW3AQuDRzOz/97eafHvDjvdz/9rXvsbNN9/csHu693a5M888kxNOOIGJEyfy6le/mgsvvBCAL37xi3z84x9nwoQJtLW1ccYZZ/Ce97xn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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance[['total_ticks', 'total_alloc']].plot.bar(\n", + " logy=False, secondary_y=['total_alloc'], \n", + " figsize=(8, 6), title=\"Internal time and memory\")\n", + "plt.savefig('internal_time_and_memory_linear.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 165, + "metadata": {}, + "outputs": [], + "source": [ + "# times = pd.read_csv('times.csv', \n", + "# names=['program', 'system', 'elapsed', 'memory'], \n", + "# index_col='program')\n", + "# times.index = times.index.str.slice(start=len('cabal run '))\n", + "# times.elapsed = pd.to_numeric(times.elapsed.str.slice(start=2))\n", + "# times" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "datetime.datetime(2022, 12, 26, 23, 59, 59)" + ] + }, + "execution_count": 166, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "today = datetime.date.today()\n", + "today = datetime.datetime(year=today.year, month=today.month, day=today.day) - datetime.timedelta(seconds=1)\n", + "today" + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "datetime.datetime(1900, 1, 1, 0, 0)" + ] + }, + "execution_count": 167, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "epoch = datetime.datetime(year=1900, month=1, day=1)\n", + "epoch" + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
systemelapsedmemory
program
advent010.000.0210488
advent020.000.0211112
advent030.000.0210408
advent040.000.019040
advent050.010.019324
advent060.010.0210124
advent070.000.019192
advent080.020.0912204
advent090.010.0623660
advent100.000.016800
advent110.070.3666664
advent120.061.0913264
advent130.010.0112300
advent140.010.8515068
advent1520.65137.2718101260
advent1615.74144.6445628
advent173.9420.6722000
advent180.020.0614060
advent1987.221134.1214295324
advent202.8115.0413940
advent210.020.4012680
advent220.020.2315908
advent231.87370.1813628
advent240.242.7474820
advent250.000.015896
\n", + "
" + ], + "text/plain": [ + " system elapsed memory\n", + "program \n", + "advent01 0.00 0.02 10488\n", + "advent02 0.00 0.02 11112\n", + "advent03 0.00 0.02 10408\n", + "advent04 0.00 0.01 9040\n", + "advent05 0.01 0.01 9324\n", + "advent06 0.01 0.02 10124\n", + "advent07 0.00 0.01 9192\n", + "advent08 0.02 0.09 12204\n", + "advent09 0.01 0.06 23660\n", + "advent10 0.00 0.01 6800\n", + "advent11 0.07 0.36 66664\n", + "advent12 0.06 1.09 13264\n", + "advent13 0.01 0.01 12300\n", + "advent14 0.01 0.85 15068\n", + "advent15 20.65 137.27 18101260\n", + "advent16 15.74 144.64 45628\n", + "advent17 3.94 20.67 22000\n", + "advent18 0.02 0.06 14060\n", + "advent19 87.22 1134.12 14295324\n", + "advent20 2.81 15.04 13940\n", + "advent21 0.02 0.40 12680\n", + "advent22 0.02 0.23 15908\n", + "advent23 1.87 370.18 13628\n", + "advent24 0.24 2.74 74820\n", + "advent25 0.00 0.01 5896" + ] + }, + "execution_count": 168, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "times = pd.read_csv('times_raw.csv', \n", + " names=['program', 'system', 'elapsed', 'memory'], \n", + " index_col='program')\n", + "times.elapsed = (pd.to_datetime(times.elapsed, format=\"%M:%S.%f\") - epoch)\n", + "times.elapsed = times.elapsed.apply(lambda x: x.total_seconds())\n", + "times" + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "system float64\n", + "elapsed float64\n", + "memory int64\n", + "dtype: object" + ] + }, + "execution_count": 169, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "times.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
systemelapsedmemory
count25.00000025.0000002.500000e+01
mean5.30920073.1176001.313392e+06
std17.799571235.4104424.513418e+06
min0.0000000.0100005.896000e+03
25%0.0000000.0200001.040800e+04
50%0.0200000.0900001.326400e+04
75%0.2400002.7400002.200000e+04
max87.2200001134.1200001.810126e+07
\n", + "
" + ], + "text/plain": [ + " system elapsed memory\n", + "count 25.000000 25.000000 2.500000e+01\n", + "mean 5.309200 73.117600 1.313392e+06\n", + "std 17.799571 235.410442 4.513418e+06\n", + "min 0.000000 0.010000 5.896000e+03\n", + "25% 0.000000 0.020000 1.040800e+04\n", + "50% 0.020000 0.090000 1.326400e+04\n", + "75% 0.240000 2.740000 2.200000e+04\n", + "max 87.220000 1134.120000 1.810126e+07" + ] + }, + "execution_count": 170, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "times.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 171, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
total_timetotal_alloctotal_ticksinitial_capabilitiessystemelapsedmemory
program
advent010.0611516576192120.000.0210488
advent020.069613016192120.000.0211112
advent030.046018112120120.000.0210408
advent040.03291382496120.000.019040
advent050.02339688884120.010.019324
advent060.02502588884120.010.0210124
advent070.033049136108120.000.019192
advent080.692145975122352120.020.0912204
advent090.37397082561248120.010.0623660
advent100.0163180848120.000.016800
advent113.0265581283210308120.070.3666664
advent127.58159890240025836120.061.0913264
advent130.0810281760264120.010.0112300
advent145.8025816968019788120.010.8515068
advent1523014.42126607950592784806841220.65137.2718101260
advent16910.4229613705380031045921215.74144.6445628
advent17198.3477649009464676368123.9420.6722000
advent180.36682440961224120.020.0614060
advent19125807.2719645311222964290110041287.221134.1214295324
advent20116.9355860434768398748122.8115.0413940
advent211.973511358246720120.020.4012680
advent223671.9452844510528812521556120.020.2315908
advent231977.02263874465046741780121.87370.1813628
advent2418.13326807233661836120.242.7474820
advent250.0164249648120.000.015896
\n", + "
" + ], + "text/plain": [ + " total_time total_alloc total_ticks initial_capabilities \\\n", + "program \n", + "advent01 0.06 11516576 192 12 \n", + "advent02 0.06 9613016 192 12 \n", + "advent03 0.04 6018112 120 12 \n", + "advent04 0.03 2913824 96 12 \n", + "advent05 0.02 3396888 84 12 \n", + "advent06 0.02 5025888 84 12 \n", + "advent07 0.03 3049136 108 12 \n", + "advent08 0.69 214597512 2352 12 \n", + "advent09 0.37 39708256 1248 12 \n", + "advent10 0.01 631808 48 12 \n", + "advent11 3.02 655812832 10308 12 \n", + "advent12 7.58 1598902400 25836 12 \n", + "advent13 0.08 10281760 264 12 \n", + "advent14 5.80 258169680 19788 12 \n", + "advent15 23014.42 126607950592 78480684 12 \n", + "advent16 910.42 296137053800 3104592 12 \n", + "advent17 198.34 77649009464 676368 12 \n", + "advent18 0.36 68244096 1224 12 \n", + "advent19 125807.27 1964531122296 429011004 12 \n", + "advent20 116.93 55860434768 398748 12 \n", + "advent21 1.97 351135824 6720 12 \n", + "advent22 3671.94 528445105288 12521556 12 \n", + "advent23 1977.02 26387446504 6741780 12 \n", + "advent24 18.13 3268072336 61836 12 \n", + "advent25 0.01 642496 48 12 \n", + "\n", + " system elapsed memory \n", + "program \n", + "advent01 0.00 0.02 10488 \n", + "advent02 0.00 0.02 11112 \n", + "advent03 0.00 0.02 10408 \n", + "advent04 0.00 0.01 9040 \n", + "advent05 0.01 0.01 9324 \n", + "advent06 0.01 0.02 10124 \n", + "advent07 0.00 0.01 9192 \n", + "advent08 0.02 0.09 12204 \n", + "advent09 0.01 0.06 23660 \n", + "advent10 0.00 0.01 6800 \n", + "advent11 0.07 0.36 66664 \n", + "advent12 0.06 1.09 13264 \n", + "advent13 0.01 0.01 12300 \n", + "advent14 0.01 0.85 15068 \n", + "advent15 20.65 137.27 18101260 \n", + "advent16 15.74 144.64 45628 \n", + "advent17 3.94 20.67 22000 \n", + "advent18 0.02 0.06 14060 \n", + "advent19 87.22 1134.12 14295324 \n", + "advent20 2.81 15.04 13940 \n", + "advent21 0.02 0.40 12680 \n", + "advent22 0.02 0.23 15908 \n", + "advent23 1.87 370.18 13628 \n", + "advent24 0.24 2.74 74820 \n", + "advent25 0.00 0.01 5896 " + ] + }, + "execution_count": 171, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "performance = performance.merge(times, left_index=True, right_index=True)\n", + "# performance.drop(index='advent15loop', inplace=True)\n", + "performance" + ] + }, + { + "cell_type": "code", + "execution_count": 172, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['total_time', 'total_alloc', 'total_ticks', 'initial_capabilities',\n", + " 'system', 'elapsed', 'memory'],\n", + " dtype='object')" + ] + }, + "execution_count": 172, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "performance.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance.elapsed.plot.bar(\n", + " figsize=(8, 6), title=\"External time\")\n", + "plt.savefig('external_time.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 174, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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gAMO4D//8z/JTABuv/12APbZZ581hzruvPNOli5d2pTHLUla/zii0A877LAD//qv/8r+++/PK6+8wqhRo/jOd76zpv/AAw9k3rx5TJ06le22244999xzTd+4ceO466672H333Rk/fjwLFy5k9erVHHbYYTz11FNkJp/97Gd57Wtfy4knnshnPvMZpk6dSmYyadIkfvazn/Hxj3+cI488kqlTp7LLLrswbdq0oXgapOY6eXyn5aeGJo8a6Hyll1dqaTBFx7fVuho3blw+99xza7Xdc889bL/99kOU0cBsvPHGPPvss0OdxpBq5ddPQ8hCYQ0LheEtIv6cmeOGOo8OHnqQJEmVLBSabH0fTZAktRYLBUmSVMlCQZIkVfKqB0mSWkhEnAX8A/BoZu7URf9xwKHl4khge2DzzHw8IpYDzwCrgfbM3KOn/TmiIElSa1kAHFjVmZn/lpm7ZOYuwBeAazPz8YZV9iv7eywSwEJhvfLtb3+bc845p8u+efPmVfZ1WLBgAccee2yXfV/96lfXzL/00kvss88+tLe39z9ZSVKXMvM64PEeVyzMBs4fyP6Gx6GHztdXDzhe61yf3d7ezsiRPb+M7e3tnHXWWdx2221d9n3sYx8bUB5f/epXOeGEEwAYPXo0M2bMYOHChRx66KE9bClJGgwRMZZi5KHxG14CV0REAv+VmfO73LiBIwr9sHz5ct7ylrdw9NFHs9NOO3HooYdy1VVXsffeezNlyhRuvvlmoPo20QsWLGDmzJkcfPDBTJ48mdNPP51vfetb7Lrrruy55548/nhRKC5ZsoQ999yTqVOn8p73vIcnnngCgOnTp3PCCSew7777csoppzB58mRefvllAJ5++mkmTZq0ZrnDL3/5S3bbbbc1RUVjjFNPPZWTTz55zc2nbrnlFqZOncpee+3Fcccdx047/eUQ2MqVKznwwAOZMmUKn//85wE4/vjjef7559lll13WFAYzZ8581R01JUm9MjIiFjdMc/oZ52Dg+k6HHfbOzN2Ag4BjImKfnoJYKPTTsmXL+PSnP83SpUu59957Oe+88/jNb37DN7/5zTXD8FW3iYbiHg3nnXceN998M1/84hcZO3Yst99+O3vttdeaQwCHH344X//611m6dClvfetb19ySGuDJJ5/k2muv5aSTTmL69OlcemnxS20XXHAB73vf+xg1atRa+V5//fXsvvvua7V1xPjc5z63VvuRRx7JvHnzuOGGGxgxYsRafUuWLGHhwoXccccdLFy4kBUrVjB37lw22mgjlixZsqY42GmnnbjlllsG+jRL0vqoPTP3aJh6/NZfYRadDjtk5sry76PAxUCP9wCwUOinyZMn89a3vpUNNtiAHXfckRkzZhARvPWtb2X58uVAcZvouXPnsssuu6y5g+RDDz0EwH777ccmm2zC5ptvzvjx4zn44IMB1mz/1FNP8eSTT7LvvvsCcMQRR3Ddddet2X/HraoBjj76aL7//e8D8P3vf58jjzzyVfk+/PDDbL755mu1Ncbo8OSTT/LMM8/wt3/7twB8+MMfXqt/xowZjB8/njFjxrDDDjusdTOsRiNGjGD06NE888wz1U+iJGlQRMR4YF/gkoa2cRGxScc8sD9wZ0+xhsc5CkNgww03XDO/wQYbrFneYIMN1pzEV3Wb6JtuuqlX23dn3Li//Az43nvvzfLly7n22mtZvXr1WocKOmy00UavutV1Y4wOPd37ozHvESNGdJvriy++yJgxY7qNJ0nqm4g4H5gObBYRbcBJwCiAzJxXrvYe4IrMbLxZ0pbAxREBxef/eZn5857254jCIKq6TXRvjB8/ngkTJvDrX/8agHPPPXfN6EJXDj/8cGbPnt3laALA9ttvz7Jly3rc74QJE9hkk03W3Br7ggsu6FW+o0aNWuu8iFWrVrH55pu/6hCIJGlgMnN2Zm6VmaMyc2Jmfi8z5zUUCWTmgsyc1Wm7BzJz53LaMTNP6c3+LBQG0YknnsjLL7/M1KlT2WmnnTjxxBP7tP3ZZ5/Ncccdx9SpU1myZAlf+tKXKtc99NBDeeKJJ5g9e3aX/QcddNBahy66873vfY85c+aw1157kZmMH9/zVSVz5sxh6tSpa05mvOaaa3jXu97Vq/1JkurL20wPExdddBGXXHIJ5557buU673nPe/jGN77BlClTuo317LPPsvHGGwMwd+5cHn74YU499dQ+5fPe976Xr33ta6867AK+fuonbzO9hreZHt7qdptpz1EYBj75yU9y+eWXc9lll3W7XseHfk+FwqWXXsrXvvY12tvb2XbbbVmwYEGf8nnppZeYOXNml0WCJKm1OKKgpvP1U784orCGIwrDW91GFDxHQZIkVWrZQqHuIyHqmq+bJLWWliwUxowZw6pVq/zQaTGZyapVq/xtBUlqIS15MuPEiRNpa2vjscceG+pU1Edjxoxh4sSJQ52GJKmXWrJQGDVqFJMnTx7qNCRJGvZa8tCDJElqDgsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZV6LBQi4qyIeDQi7mxoe11EXBkR95d/JzT0fSEilkXEfRFxQEP77hFxR9l3WkTEun84kiRpXerNiMIC4MBObccDV2fmFODqcpmI2AGYBexYbnNGRIwotzkTmANMKafOMSVJUs30WChk5nXA452aDwHOLufPBmY2tF+QmS9m5oPAMmBaRGwFvCYzb8jiTk7nNGwjSZJqqr/nKGyZmQ8DlH+3KNu3BlY0rNdWtm1dzndulyRJNbaubwrV1XkH2U1710Ei5lAcpmD06NHrJjNJktRn/R1ReKQ8nED599GyvQ3YpmG9icDKsn1iF+1dysz5mblHZu4xcmRL3uBSkqRhob+FwiLgiHL+COCShvZZEbFhREymOGnx5vLwxDMRsWd5tcPhDdtIkqSa6vHrekScD0wHNouINuAkYC5wYUQcBTwEfAAgM++KiAuBu4F24JjMXF2G+jjFFRQbAZeXkyRJqrEeC4XMnF3RNaNi/VOAU7poXwzs1KfsJEnSkPKXGSVJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSWohEXFWRDwaEXdW9E+PiKciYkk5famh78CIuC8ilkXE8b3Zn4WCJEmtZQFwYA/r/Dozdymn/wMQESOA7wAHATsAsyNih552ZqEgSVILyczrgMf7sek0YFlmPpCZLwEXAIf0tJGFgiRJw89eEfG7iLg8InYs27YGVjSs01a2davHm0JJkqSmGhkRixuW52fm/D5sfxuwbWY+GxHvAn4KTAGii3Wzx2T6sGNJkjT42jNzj/5unJlPN8xfFhFnRMRmFCMI2zSsOhFY2VM8Dz1IkjSMRMTrIyLK+WkUn/WrgFuAKRExOSJGA7OART3Fc0RBkqQWEhHnA9OBzSKiDTgJGAWQmfOA9wMfj4h24HlgVmYm0B4RxwK/AEYAZ2XmXT3tz0JBkqQWkpmze+g/HTi9ou8y4LK+7M9DD5IkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIq+TsKktTqTh7fafmpoclDw5IjCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKnSgAqFiPhsRNwVEXdGxPkRMSYiXhcRV0bE/eXfCQ3rfyEilkXEfRFxwMDTlyRJg6nfhUJEbA18CtgjM3cCRgCzgOOBqzNzCnB1uUxE7FD27wgcCJwRESMGlr4kSRpMAz30MBLYKCJGAmOBlcAhwNll/9nAzHL+EOCCzHwxMx8ElgHTBrh/SZI0iPpdKGTmH4FvAg8BDwNPZeYVwJaZ+XC5zsPAFuUmWwMrGkK0lW2SJKmmBnLoYQLFKMFk4A3AuIg4rLtNumjLithzImJxRCxub2/vb4qSJGmABnLo4R3Ag5n5WGa+DPwE+FvgkYjYCqD8+2i5fhuwTcP2EykOVbxKZs7PzD0yc4+RI0cOIEVJkoaXiDgrIh6NiDsr+g+NiKXl9NuI2Lmhb3lE3BERSyJicW/2N5BC4SFgz4gYGxEBzADuARYBR5TrHAFcUs4vAmZFxIYRMRmYAtw8gP1LkrQ+WkBxUUCVB4F9M3Mq8BVgfqf+/TJzl8zcozc76/fX9cy8KSIuAm4D2oHby2Q2Bi6MiKMoiokPlOvfFREXAneX6x+Tmav7u39JktZHmXldREzqpv+3DYs3Uozg99uAxvUz8yTgpE7NL1KMLnS1/inAKQPZpyRJ6rWjgMsblhO4IiIS+K/M7Dza8CqeACBJUr2M7HT+wPzefKB3FhH7URQKb29o3jszV0bEFsCVEXFvZl7XbTJ93bEkSRpU7b09f6BKREwFvgsclJmrOtozc2X599GIuJji94y6LRS814MkScNIRLyR4krEj2Tm7xvax0XEJh3zwP5Al1dONHJEQZKkFhIR5wPTgc0ioo3iXMFRAJk5D/gSsCnFrRLgLyMUWwIXl20jgfMy8+c97c9CQZKkFpKZs3voPxo4uov2B4CdX71F9zz0IEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIktZCIOCsiHo2IOyv6IyJOi4hlEbE0InZr6DswIu4r+47vzf4sFCRJai0LgAO76T8ImFJOc4AzASJiBPCdsn8HYHZE7NDTziwUJElqIZl5HfB4N6scApyThRuB10bEVsA0YFlmPpCZLwEXlOt2y0JBkqThZWtgRcNyW9lW1d6tkes0NUmSNFAjI2Jxw/L8zJzfh+2ji7bspr37ZPqwY0mSNPjaM3OPAWzfBmzTsDwRWAmMrmjvloceJEkaXhYBh5dXP+wJPJWZDwO3AFMiYnJEjAZmlet2a0CFQkS8NiIuioh7I+KeiNgrIl4XEVdGxP3l3wkN63+hvCTjvog4YCD7liRpfRQR5wM3ANtFRFtEHBURH4uIj5WrXAY8ACwD/i/wCYDMbAeOBX4B3ANcmJl39bS/gR56OBX4eWa+v6xOxgInAFdn5tzyGs3jgX8uL8GYBewIvAG4KiLenJmrB5iDJEnrjcyc3UN/AsdU9F1GUUj0Wr9HFCLiNcA+wPfKnb+UmU9SXGpxdrna2cDMcv4Q4ILMfDEzH6SodKb1d/+SJGnwDeTQw5uAx4DvR8TtEfHdiBgHbFkeC6H8u0W5fr8uy5AkSUNnIIXCSGA34MzM3BV4juIwQ5VeX5YREXMiYnFELG5vbx9AipIkaSAGUii0AW2ZeVO5fBFF4fBI+QtQlH8fbVi/V5dlZOb8zNwjM/cYOdIrOCVJGir9LhQy83+AFRGxXdk0A7ib4lKLI8q2I4BLyvlFwKyI2DAiJlP8BvXN/d2/JEkafAP9uv5J4IflFQ8PAEdSFB8XRsRRwEPABwAy866IuJCimGgHjvGKB0mS6m1AhUJmLgG6+vWoGRXrnwKcMpB9SpKk5vGXGSVJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZUsFCRJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZUsFCRJUiULBUmSVMlCQZIkVbJQkCSpxUTEgRFxX0Qsi4jju+g/LiKWlNOdEbE6Il5X9i2PiDvKvsU97WvkYDwASZI0OCJiBPAd4J1AG3BLRCzKzLs71snMfwP+rVz/YOCzmfl4Q5j9MvNPvdmfIwqSJLWWacCyzHwgM18CLgAO6Wb92cD5/d2ZhYIkSa1la2BFw3Jb2fYqETEWOBD4cUNzAldExK0RMaennXnoQZKkehnZ6dyB+Zk5v2E5utgmK2IdDFzf6bDD3pm5MiK2AK6MiHsz87rKZHqdtiRJaob2zNyjm/42YJuG5YnAyop1Z9HpsENmriz/PhoRF1McyqgsFDz0IElSa7kFmBIRkyNiNEUxsKjzShExHtgXuKShbVxEbNIxD+wP3NndzhxRkCSphWRme0QcC/wCGAGclZl3RcTHyv555arvAa7IzOcaNt8SuDgioKgBzsvMn3e3PwsFSZJaTGZeBlzWqW1ep+UFwIJObQ8AO/dlXx56kCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZUsFCRJUqUBFwoRMSIibo+In5XLr4uIKyPi/vLvhIZ1vxARyyLivog4YKD7liRJg2tdjCh8GrinYfl44OrMnAJcXS4TETtQ3OFqR+BA4IyIGLEO9i9JkgbJgAqFiJgIvBv4bkPzIcDZ5fzZwMyG9gsy88XMfBBYRnEPbEmSVFMDHVH4NvB54JWGti0z82GA8u8WZfvWwIqG9drKNkmSVFP9LhQi4h+ARzPz1t5u0kVbVsSeExGLI2Jxe3t7f1OUJEkDNHIA2+4N/K+IeBcwBnhNRPwAeCQitsrMhyNiK+DRcv02YJuG7ScCK7sKnJnzgfkA48aN67KYkCRJg6/fIwqZ+YXMnJiZkyhOUvxlZh4GLAKOKFc7AriknF8EzIqIDSNiMjAFuLnfmUuSpEE3kBGFKnOBCyPiKOAh4AMAmXlXRFwI3A20A8dk5upB2L8kSVpH1kmhkJm/An5Vzq8CZlSsdwpwyrrYpyRJGnz+MqMkSapkoSBJkipZKEiSpEqDcTKjJElDYtLxl661vHzuu4cok+HDEQVJklTJQkGSJFWyUJAkSZUsFCRJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSWoxEXFgRNwXEcsi4vgu+qdHxFMRsaScvtTbbTvzplCSJLWQiBgBfAd4J9AG3BIRizLz7k6r/joz/6Gf267hiIIkSa1lGrAsMx/IzJeAC4BDBmtbCwVJkuplZEQsbpjmdOrfGljRsNxWtnW2V0T8LiIuj4gd+7jtX5LpY/KSJGlwtWfmHt30Rxdt2Wn5NmDbzHw2It4F/BSY0stt1+KIgiRJraUN2KZheSKwsnGFzHw6M58t5y8DRkXEZr3ZtjMLBUmSWsstwJSImBwRo4FZwKLGFSLi9RER5fw0is/7Vb3ZtjMPPUiS1EIysz0ijgV+AYwAzsrMuyLiY2X/POD9wMcjoh14HpiVmQl0uW13+7NQkCSpxZSHEy7r1DavYf504PTebtsdDz1IkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSapkoSBJkipZKEiSpEoWCpIkqZKFgiRJqmShIEmSKlkoSJKkShYKkiSpUr8LhYjYJiKuiYh7IuKuiPh02f66iLgyIu4v/05o2OYLEbEsIu6LiAPWxQOQJEmDZyAjCu3A5zJze2BP4JiI2AE4Hrg6M6cAV5fLlH2zgB2BA4EzImLEQJKXJEmDq9+FQmY+nJm3lfPPAPcAWwOHAGeXq50NzCznDwEuyMwXM/NBYBkwrb/7lyRJg2+dnKMQEZOAXYGbgC0z82Eoiglgi3K1rYEVDZu1lW2SJKmmBlwoRMTGwI+Bz2Tm092t2kVbVsScExGLI2Jxe3v7QFOUJEn9NKBCISJGURQJP8zMn5TNj0TEVmX/VsCjZXsbsE3D5hOBlV3Fzcz5mblHZu4xcuTIgaQoSZIGYCBXPQTwPeCezPxWQ9ci4Ihy/gjgkob2WRGxYURMBqYAN/d3/5IkafAN5Ov63sBHgDsiYknZdgIwF7gwIo4CHgI+AJCZd0XEhcDdFFdMHJOZqwewf0mSNMj6XShk5m/o+rwDgBkV25wCnNLffUqSpObylxklSVIlCwVJklTJQkGSpBYTEQeWt0NYFhHHd9F/aEQsLaffRsTODX3LI+KOiFgSEYt72pfXHkqS1ELK2x98B3gnxU8P3BIRizLz7obVHgT2zcwnIuIgYD7wNw39+2Xmn3qzP0cUJElqLdOAZZn5QGa+BFxAcZuENTLzt5n5RLl4I8VvF/WLhYIkSa2lr7dEOAq4vGE5gSsi4taImNPTzjz0IElSvYzsdO7A/Myc37Dcl1si7EdRKLy9oXnvzFwZEVsAV0bEvZl5XWUyfUhckiQNvvbM3KOb/l7dEiEipgLfBQ7KzFUd7Zm5svz7aERcTHEoo7JQ8NCDJEmt5RZgSkRMjojRwCyK2ySsERFvBH4CfCQzf9/QPi4iNumYB/YH7uxuZ44oSJLUQjKzPSKOBX4BjADOKm+T8LGyfx7wJWBT4Izi1kxrRim2BC4u20YC52Xmz7vbn4WCpGFr0vGXrrW8fO67hygTad3KzMuAyzq1zWuYPxo4uovtHgB27tzeHQ89SJKkSo4oSKqdziMBAMvHDEEikhxRkCRJ1SwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZUsFCRJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklTJQkGSJFWyUJAkSZUsFCRJUiULBUmSVMlCQZIkVbJQkCRJlSwUJElSJQsFSZJUyUJBkiRVslCQJEmVLBQkSVIlCwVJklRp5FAnIEl1N+n4S9daXj733UOUidR8TS8UIuJA4FRgBPDdzJzb7BwkaX3XufgBC6BW0tNnaURE2f8u4M/ARzPztt5s21lTDz1ExAjgO8BBwA7A7IjYoZk5SJLUynr5WXoQMKWc5gBn9mHbtTT7HIVpwLLMfCAzXwIuAA5pcg6SJLWy3nyWHgKck4UbgddGxFa93HYtzT70sDWwomG5DfibJucg1dPJ47toe6r5eUh6tXr9++zNZ2lX62zdy23X0uxCIbpoy1etFDGHYqgEICPi+R7ijgTaB5jbuohhnNaKU6dcuo7z5a7+yQxhPkMYJzrH6cdzE19fR7msozjU6LmB+j2udRFnUB/T4P373CgiFjcsz8/M+Q3LvfksrVqnV5/DjZpdKLQB2zQsTwRWdl6pfELmd26vEhGLM3OPgSS2LmIYp7Xi1CkX4zQnTp1yMU5z4tQpl3UYpzefpVXrjO7Ftmtp9jkKtwBTImJyRIwGZgGLmpyDJEmtrDefpYuAw6OwJ/BUZj7cy23X0tQRhcxsj4hjgV9QXJZxVmbe1cwcJElqZVWfpRHxsbJ/HnAZxaWRyygujzyyu22721/Tf0chMy+jeADrUq8PUwxyDOO0Vpw65WKc5sSpUy7GaU6cOuWyzuJ09VlaFggd8wkc09ttuxNFLEmSpFfzXg+SJKmShYIkSapkoSBJkipZKEiSpErDplCIiC/1cf0DIuKoiJjUqf0f+xAjIuKDEfGBcn5GRJwWEZ+IiAE9txHxy35ss1mn5cPKfOaUdxLrbZz3RMTryvnNI+KciLgjIhZGxMRexvhWROzdt0fQZZzXRcSXIuLo8jn+YkT8LCL+LSIm9DHWfhFxekRcEhE/joi5EfHX/cjpgIg4MyIWlbHOLO/Gtk4Mp/dyq7+Py219L/fDcHofl7GH7L081IbNVQ8R8VBmvrGX634VeDtwG3Aw8O3M/M+y77bM3K2Xcc4AtqD4paungQ2B/6a4dvWRzPx0L+Ms7dwEvBm4DyAzp/YyzprcI+JfgL8DzgP+AWjLzM/2Ms7dmblDOb8QuBH4EfAO4NDMfGcvYjwG/AHYHFgInJ+Zt/dm/53iXAbcAbwG2L6cvxB4J7BzZvbqpmIRMRfYErgamAk8CPwe+ATw1cz8US/jfJvitTmH4pfPoPhls8OB+3v7mvewj5Z8Lw/H93G5re/lfmjV93EZp1bv5SGXmS0zUbzwXU3PAO19iHMHMLKcfy3F9aT/US7f3pc45d9RwCpgdLk8sqOvl3EWAT8A3gJsC0yiuGnHtsC2fYhze8P8bcC4hvz6ks99DfO3dupb0pdcKG5xeiJwF3AvcBLw5j7ksqT8G8Af+5NL42vV8PpcX85PAO7sQ5zfV7QHxX+u6+17eTi+jxvz8b28fryPs4bv5aGeWu3Qw5PAlMx8TadpE+DhPsQZmZntAJn5JEUF+5qI+BFFJdpbHTFeBm7J4padlLFX9zZIZv4v4McUP8Sxc2YuB17OzD9k5h/6kM9GEbFrROwOjMjM5xry63U+wK8i4v9ExEbl/EwohjuB3t4uLct935+ZX8nMHYEPAmPo2w9ubVAOy24DbNwxLBkRm9K31+qVjmFo4A0Uv0hGZj5B1zdJqfJCREzrov1twAt9iPMkw+y9PEzfx+B7uTtPMszex+X6dXsvD62hrlT6MgH/Ckyr6Pt6H+L8DNi3Iv4rfYhzObBxF+2vB27ux+MbB3yLoppt68f213SatirbNwUW9yHOKOBk4KFyeoXiG8J5wBt7GeP2dfSazwYeKaf3AVcBVwJ/BOb0Ic6HKIaPrygf07vL9s2B8/oQZzfgJuDuMtYVwD1l2+6+l4fX+9j38vr7Pq7Te3mop2FzjkJflN8wyMxX3b46IrbOzD8OMP44iiGmR/u5/c7AXtnwc5wDzGcEsGFm/rkf246nqPZX9XG7jTPz2b7uryLWCIrzadojYiSwC8XQbV++sVB+C3sTsCyLby0Dyen1FPd1D4r/QP5nIPEGkEdt38vD4X1cbut7eZDV+X1cbl+b9/JQaLlCoTxTdBrFGzspbo95c/bxgRhn8OPUKZd1Gaeb+G/JzHuNU+9cjPOqbUZlMRTe2LZZZv6pmTGMU18tVShExP7AGcD9FMN1UJyl+9fAJzLzCuPUI06dclmXcXrYR6/P8l7f4tQpF+OsWXc/4FyKKwNupzj8sbzs69WVBusihnHqr+l3jxygU4F3dDzRHSJiMsVJRdsbpzZx6pTLOosTEadVdVGcrd0rwzFOnXIxTq98Azggi9sTvx+4MiI+kpk30vuTItdFDOPUXKsVCiP5y/W+jf5IceKSceoTp065rMs4RwKfA17som/2eh6nTrkYp2ejM/MugMy8KCLuAX4SEcdTXunRpBjGqblWKxTOAm6JiAsormmF4lKjWWWfceoTp065rMs4t1Bcq/7bzh0RcfJ6HqdOuRinZy9HxOs7Tl4sv/XOoLgC4a+aGMM4NddS5ygARMT2wCE0nKULLMrMu41Trzh1ymVdxYnibPMXcoBnKw/HOHXKxTi9ivMO4LHM/F2n9vHAsZl5SjNiGKcFZA2u0ezrBHy6N23GGfo4dcrFOL7mxvE1b+U4QzUNeQL9Shpu66LtduPUL06dcjGOr7lxfM1bOc5QTS11jkJEzAY+DEyOiEUNXZtQ/K63cWoSp065GKc5ceqUi3GaE6dOuQznOEOtpQoF4LcUvx++GfDvDe3PAJ3v9mWcoY1Tp1yM05w4dcrFOM2JU6dchnOcIdVyJzNKkqTmabW7RwIQEe+NiPsj4qmIeDoinomIp41Tvzh1ysU4zYlTp1yM05w4dcplOMcZMkN9kkR/JmAZsL1x6h+nTrkYx9fcOL7mrRxnqKaWHFEAHsnMe4zTEnHqlItxmhOnTrkYpzlx6pTLcI4zJFryHIWIOJXi/uI/peFnTDPzJ8apV5w65WKc5sSpUy7GaU6cOuUynOMMlVa76qHDa4A/A/s3tCXQ1yfdOIMfp065GKc5ceqUi3GaE6dOuQznOEOiJUcUJElSc7TkOQoR8eaIuDoi7iyXp0bEvxinfnHqlItxmhOnTrkYpzlx6pTLcI4zZIb6bMr+TMC1wDQafgKT4m5qxqlZnDrlYhxfc+P4mrdynKGaWnJEARibmTd3ams3Ti3j1CkX4zQnTp1yMU5z4tQpl+EcZ0i0aqHwp4j4K4qTQYiI91P8TKZx6henTrkYpzlx6pSLcZoTp065DOc4Q2OohzT6MwFvAq6iOIv0j8BvgG2NU784dcrFOL7mxvE1b+U4QzW15FUPETEiM1dHxDhgg8x8xjj1jFOnXIzTnDh1ysU4zYlTp1yGc5yh0qqHHh6MiPnAnsCzxql1nDrlYpzmxKlTLsZpTpw65TKc4wyJVi0UtqMYxjmG4gU4PSLebpxaxqlTLsZpTpw65WKc5sSpUy7DOc7QGOpjHwOdgAnAOcBq49Q7Tp1yMY6vuXF8zVs5TjOnVh1RICL2jYgzgNuAMcAHjVPPOHXKxTjNiVOnXIzTnDh1ymU4xxkKrXoy44PAEuBCYFFmPmecesapUy7GaU6cOuVinObEqVMuwznOUGnVQuE1mfm0ceofp065GKc5ceqUi3GaE6dOuQznOEOlpQqFiPhPyh+s6Epmfso49YhTp1yM05w4dcrFOM2JU6dchnOcodZq5ygsBm6lOL6zG3B/Oe0CrDZOreLUKRfjNCdOnXIxTnPi1CmX4RxnaA312ZT9mYBrgFENy6OAa4xTvzh1ysU4vubG8TVv5ThDNbXaiEKHNwCbNCxvXLYZp35x6pSLcZoTp065GKc5ceqUy3COMyRGDnUC/TQXuD0irimX9wVONk4t49QpF+M0J06dcjFOc+LUKZfhHGdItNTJjI0i4g3AR4B7gLHAysy8zjj1i1OnXIzTnDh1ysU4zYlTp1yGc5whMdTHPvozAUcDdwBPUBz7eR74pXHqF6dOuRjH19w4vuatHGeopiFPoF9JF0/4GGBJufwWYKFx6henTrkYx9fcOL7mrRxnqKZWPZnxhcx8ASAiNszMeyluumGc+sWpUy7GaU6cOuVinObEqVMuwznOkGjVkxnbIuK1wE+BKyPiCWClcWoZp065GKc5ceqUi3GaE6dOuQznOEOiZU9m7BAR+wLjgZ9n5kvGqW+cOuVinObEqVMuxmlOnDrlMpzjNFPLFwqSJGnwtOo5CpIkqQksFCRJUiULBUmSVMlCQVqPRMSIAW7fqldKSeonT2aUhomImAT8HLgJ2BX4PXA4cDdwFrA/cDoQwAnl30sz85/L7Y8C/pnisq37gRcz89iIWAA8Xsa8DVgIfBvYiOIX5o7MzPsi4qPATGAEsBPw78Boip+tfRF4V2Y+PnjPgKTB4LcDaXjZDjgqM6+PiLOAT5TtL2Tm28vfm78R2J3i52SviIiZwM3AicBuwDPAL4HfNcR9M/COzFwdEa8B9snM9oh4B/BV4H3lejtRFBRjgGXAP2fmrhHxHxRFy7cH6XFLGiQWCtLwsiIzry/nfwB8qpxfWP59G/CrzHwMICJ+COxT9l3b8Y0/In5EURx0+FFmri7nxwNnR8QUIIFRDetdk5nPAM9ExFPAf5ftdwBT18UDlNRcnqMgDS+djyV2LD9X/o2K7araOzzXMP8VioJgJ+BgitGDDi82zL/SsPwKfjGRWpKFgjS8vDEi9irnZwO/6dR/E7BvRGxWntg4G7iW4tDDvhExoTxh8X1UGw/8sZz/6DrLXFItWShIw8s9wBERsRR4HXBmY2dmPgx8geJWt78DbsvMSzLzjxTnGtwEXEVxAuRTFfv4BvC1iLie4sRFScOYVz1Iw0R51cPPykMC/dl+48x8thxRuBg4KzMvXpc5Smo9jihI6nByRCwB7gQepLjTnaT1nCMKkiSpkiMKkiSpkoWCJEmqZKEgSZIqWShIkqRKFgqSJKmShYIkSar0/wNOFIlAvJhJZwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['elapsed', 'memory']].plot.bar(\n", + " logy=False, secondary_y=['memory'], \n", + " figsize=(8, 6), title=\"External time and memory\")\n", + "plt.savefig('external_time_and_memory.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 175, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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jYEkabKIiIcys3v4Z04c5xhIkqQaGwNJklRT5ByD7Xnsscfo6enhkUceaXUpGqHp06czc+ZMpkyZ0upSJElDaLvGoKenh1133ZVZs2ZRvd672kBmcvfdd9PT08Ps2bNbXY4kaQhttyvhkUceYffdd7cpaDMRwe677+5IjyQVru0aA8CmoE35vklS+dqyMSjRrFmz+OMf/9j0112wYAFXX311019XktSZ2m6OwUCzlq4d17zNy44d1zxJktqJIwaj8OUvf5n58+ez//778y//8i/09fVt8/iiRYs46KCDeP7zn8/y5f99ifZddtmFd7/73Rx44IEcfvjh3HXXXQCcc845zJ07l3nz5nHCCScA8OCDD/LGN76Rgw8+mAMOOIBvfetbADz88MOccMIJzJs3j+OPP56HH275SbIkSeOnKyKWV88A3BJtP2LQbBs3bmTVqlVceeWVTJkyhbe+9a185Stf2eY5K1as4ClPeQoPP/wwBx98MK961avYfffdefDBBznwwAP55Cc/yb//+7/zoQ99iHPPPZdly5bx29/+lmnTprF161YAPvrRj/J3f/d3rFixgq1btzJ//nyOOOIIPv/5z7Pzzjtz/fXXc/3113PggQe24LcgSZogfZm5pJUF2BiM0Pe//31+8YtfcPDBBwOVb/BPe9rTtnnOOeecwze+8Q0AtmzZwm9+8xt23313dthhB44//ngAXvva1/LKV74SgHnz5nHiiSeyaNEiFi1aBMD3vvc9Vq9ezSc+8QmgcjTG73//e9avX8/b3/722nbz5s2b8J9ZkjR5NK0xiIh9gHcATwW+n5mfa9Zrj6fM5PWvfz1nnXXWNutXrlwJwA9/+EMuv/xyrrrqKnbeeWcWLFgw5CF6/bP0165dy/r161m9ejUf/vCHuemmm8hMvva1r7H33nsPuZ0kSeNtTHMMImJFRNwZETcOWH90RNwSEZsiYilAZm7MzDcDrwZeMJbXbaXDDz+cyy67jDvvvBOAe+65h9/97ne1x++77z522203dt55Z26++WZ++tOf1h57/PHHueyyywC46KKLePGLX8zjjz/Oli1beOlLX8rHP/5xtm7dygMPPMBRRx3FZz7zGfovcnXttdcC8JKXvKS26+LGG2/k+uuvb8rPLbXUGTO2vU1is5au3eYmjbexjhisBM4FLuhfERFdwHnAy4AeYENErM7MX0XEPwBLq9u0pblz5/KRj3yEI488kscff5wpU6Zw3nnn1R4/+uijOf/885k3bx577703hxxySO2x7u5ubrrpJg466CBmzJjBqlWr6Ovr47WvfS333Xcfmcm73vUunvzkJ3P66afzzne+k3nz5pGZzJo1i29/+9u85S1v4aSTTmLevHnsv//+zJ8/vxW/BklShxrzZZcjYhbw7czct7p8KHBGZh5VXf5XgMw8q26btZk57HGBg112eePGjeyzzz5jqrlVdtllFx544IFWl9FS7fz+qYUGjhKccV9r6ijAwFECD7HuLCVcdnki5hjsCWypW+4BXhgRC4BXAtOAdUNtHBFLgCUAU6dOnYDyJEnSUCaiMRhsZlxm5g+BHw63cWYuB5ZDZcRgXCtrsck+WiBJKt9EnOCoB9irbnkmcPsEvI4kSRpnE9EYbADmRMTsiJgKnACsHklARCyMiOUDzygoSZIm1lgPV7wYuArYOyJ6IuLkzOwFTgW+C2wELs3Mm0aSm5lrMnNJV1fXWMqTJEkjNKY5Bpm5eIj169jOBENJklSmIi+i5K6E8ffpT3+aCy64YNDHzj///CEf67dy5UpOPfXUQR8788wza/cfffRRXvKSl9Db2zv6YiU1zpM/aZwVea2EzFwDrOnu7j5l2CeP9/8IbXR8dG9vLzvuOPxb2Nvby4oVK7jmmmsGfezNb37zmOo488wzed/73gdUDjE9/PDDWbVqFSeeeOKYciVJzVfkiEHJNm/ezPOe9zze9KY3se+++3LiiSdy+eWX86IXvYg5c+bw85//HBj6sskrV65k0aJFLFy4kNmzZ3PuuefyqU99igMOOIBDDjmEe+65B4DrrruOQw45hHnz5vGKV7yCe++9F4AFCxbwvve9j8MOO4yPfvSjzJ49m8ceewyAP/3pT8yaNau23O8HP/gBBx54YK2JqM84++yzOeOMM2oXa9qwYQPz5s3j0EMP5bTTTmPfffet5dx+++0cffTRzJkzh/e85z0ALF26lIcffpj999+/1ggsWrToCVeclCS1hyIbg9J3JWzatIl3vOMdXH/99dx8881cdNFF/OQnP+ETn/hEbVi9/7LJGzZs4IorruC0006j/yyON954IxdddBE///nPef/738/OO+/Mtddey6GHHlob0n/d617Hxz72Ma6//nr2228/PvShD9Vef+vW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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['elapsed', 'memory']].plot.bar(\n", + " logy=True, secondary_y=['memory'], \n", + " figsize=(8, 6), title=\"External time and memory\")\n", + "plt.savefig('external_time_and_memory_log.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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gAMO4D//8z/JTABuv/12APbZZ581hzruvPNOli5d2pTHLUla/zii0A877LAD//qv/8r+++/PK6+8wqhRo/jOd76zpv/AAw9k3rx5TJ06le22244999xzTd+4ceO466672H333Rk/fjwLFy5k9erVHHbYYTz11FNkJp/97Gd57Wtfy4knnshnPvMZpk6dSmYyadIkfvazn/Hxj3+cI488kqlTp7LLLrswbdq0oXgapOY6eXyn5aeGJo8a6Hyll1dqaTBFx7fVuho3blw+99xza7Xdc889bL/99kOU0cBsvPHGPPvss0OdxpBq5ddPQ8hCYQ0LheEtIv6cmeOGOo8OHnqQJEmVLBSabH0fTZAktRYLBUmSVMlCQZIkVfKqB0mSWkhEnAX8A/BoZu7URf9xwKHl4khge2DzzHw8IpYDzwCrgfbM3KOn/TmiIElSa1kAHFjVmZn/lpm7ZOYuwBeAazPz8YZV9iv7eywSwEJhvfLtb3+bc845p8u+efPmVfZ1WLBgAccee2yXfV/96lfXzL/00kvss88+tLe39z9ZSVKXMvM64PEeVyzMBs4fyP6Gx6GHztdXDzhe61yf3d7ezsiRPb+M7e3tnHXWWdx2221d9n3sYx8bUB5f/epXOeGEEwAYPXo0M2bMYOHChRx66KE9bClJGgwRMZZi5KHxG14CV0REAv+VmfO73LiBIwr9sHz5ct7ylrdw9NFHs9NOO3HooYdy1VVXsffeezNlyhRuvvlmoPo20QsWLGDmzJkcfPDBTJ48mdNPP51vfetb7Lrrruy55548/nhRKC5ZsoQ999yTqVOn8p73vIcnnngCgOnTp3PCCSew7777csoppzB58mRefvllAJ5++mkmTZq0ZrnDL3/5S3bbbbc1RUVjjFNPPZWTTz55zc2nbrnlFqZOncpee+3Fcccdx047/eUQ2MqVKznwwAOZMmUKn//85wE4/vjjef7559lll13WFAYzZ8581R01JUm9MjIiFjdMc/oZ52Dg+k6HHfbOzN2Ag4BjImKfnoJYKPTTsmXL+PSnP83SpUu59957Oe+88/jNb37DN7/5zTXD8FW3iYbiHg3nnXceN998M1/84hcZO3Yst99+O3vttdeaQwCHH344X//611m6dClvfetb19ySGuDJJ5/k2muv5aSTTmL69OlcemnxS20XXHAB73vf+xg1atRa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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['elapsed', 'memory']].plot.bar(\n", + " logy=False, secondary_y=['memory'], \n", + " figsize=(8, 6), title=\"External time and memory\")\n", + "plt.savefig('external_time_and_memory_linear.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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/RwxkCSpxRwxkCQ1xYsvvkhPTw9r165tdymqw5gxYxg3bhybb755u0upm4cSJKmD9PT0sM022zB+/HgqC2OqrDKTJ554gp6eHnbaaad2l1O3tp4qkZkLM3NmV1dXO8uQpI6xdu1atttuOzsFHSAi2G677TpudKeU51BKkgZmp6BzdOJn5aEESZJU1daOQXFRh4Xd3d0ntLMOSepU42dd1dS8FbMPHfT5p59+mosvvphPfepTA2esWMHPf/5zjj322MH3tWIFhx12GHfffXe/z99+++2sWrWK973vfQAsWLCAe+65h1mzZg0rT/XxUIIkqW5PP/003/zmNwd9zYoVK7j44osb3tftt9/OokWLqo/f//73D9gpUPO0tWMQEYdHxJze3t52liFJqtOsWbP47//+b6ZMmcJnP/tZPvvZzzJp0iTe/va3M3/+/OprbrjhBqZMmcLXvvY1VqxYwTvf+U723HNP9txzT37+859vcD8vvPACp5xyCvPnz2fKlCnMnz+fefPmceKJJwLwyCOP8IEPfIDdd9+d3Xff/RWZDzzwAHvssQdLlixh2bJlTJ06lSlTpjB58mTuv//+5r8xGxEPJUiS6jZ79mzuvvtubr/9di6//HLOO+887rjjDh5//HH22Wcf3vWudzF79my++tWvcuWVVwLw3HPPcc011zBmzBjuv/9+ZsyYwdKlSwfdz+jRo/mnf/onli5dytlnnw3AvHnzqs+fdNJJTJs2jR/+8If09vayZs0annrqKQDuu+8+jjnmGL797W8zZcoU/vZv/5ZPf/rTfOQjH+GFF17AP0YH5wWOJEnDcuONNzJjxgy6urp4/etfz7Rp01iyZAnbbrvty1734osvcuKJJ3L77bfT1dXFb37zm4b3fe2113LhhRcC0NXVxdixY3nqqad47LHHOOKII7j88st529veBsA73vEOTj/9dHp6ejjqqKOYMGFCw/svm4jYDfg0sD3w08w8d7hZdgwkqYT6TipcMaYykW+32sbTVreuoH7Ue0n9r33ta7z+9a/njjvu4KWXXmLMmDEjVtPYsWPZcccduemmm6odg2OPPZZ9992Xq666ikMOOYTzzz+fd7/73SNWQ7NExFzgMODRzJxU0z4dOBPoAs7PzNmZeS/wyYjYDPj3RvbrHANJUt222WYbnnnmGQDe9a53MX/+fHp7e3nsscdYvHgxU6dOfdlrAFavXs0b3/hGNttsM77zne/UPZTfN6fWgQceyLnnVv4o7u3t5fe//z1QOQRxxRVXcOGFF1YnQD7wwAPsvPPOnHTSSbz//e/nzjvvHPbP32LzgOm1DRHRBZwDvBeYCMyIiInFc+8HbgR+2shOnWMgSR1sQ6cXNtt2223Hn/3ZnzFp0iTe+973MnnyZHbffXcigjPOOIM3vOENbLfddowaNYrdd9+d4447jk996lMcffTRfP/73+eAAw6gu7u+tYMOOOAAZs+ezZQpU/j85z//sufOPPNMZs6cyQUXXEBXVxfnnnsub3zjGwHo7u7myiuv5OCDD6a7u5t77rmHiy66iM0335w3vOENnHLKKU1/X0ZCZi6OiPF9mqcCyzPzAYCIuBQ4ArgnMxcACyLiKmDYp4W4uqIkldBAhxJeps2HElSfe++9l912e9lBICLiBeCumqY5mTmn77ZFx+DK9YcSIuKDwPTM/ETx+C+AfYHLgKOALYA7M/Oc4dbrHANJklpvXWbuPYzt+rvGcmbm9cD1DVVUsGMgSWqrq6++ms997nMva9tpp5344Q9/2KaKSq0H2LHm8ThgVTN3YMdAktRWhxxyCIcccki7y2i1roiYAyws5tvVawkwISJ2Ah4CjgEGv/b0ELmIkiRJrdebmTMHe0FEXALsD2wfET3AqZl5QUScCFxN5XTFuZm5rJmFeVaCJEkllJkzBmhfBCzq77lmcBElSZJarysi5hQj56Vix0CS1BTjx4/n8ccfb/l+999//wHXXvjgBz/IAw880O9zn/jEJ7jnnnsGzT7uuOO47LLLXtHedwXJu+66i+OOO67+ootDCUOcX9ASTj6UpE522tgm520810ZYtmwZvb297Lzzzq94rre3l/PPP3/Y2es7BsceW5n39/a3v52enh4efPBB3vzmNw87twwcMZAkDclFF11UXcb4r//6r/u9xPGRRx7JXnvtxdve9jbmzPnf6/ZsvfXW/N3f/R177rknBx54II899hgAZ511FhMnTmTy5Mkcc8wxADz77LN8/OMfZ5999mGPPfbgRz/6EQDPP/88xxxzDJMnT+bDH/4wzz//fL91fve73+WII4542b5POeUU9t13X26++eaXjTRccMEF7LLLLuy///6ccMIJ1eWdARYvXsyf/umfsvPOO1dHD/ouLQ1w+OGHc+mll9b7NnooQZLU+e69917mz5/PTTfdVF0t8bvf/e4rXjd37lxuueUWli5dyllnncUTTzwBVH7Z77nnntx6661MmzaNL37xi0BlOefbbruNO++8k/POOw+A008/nXe/+90sWbKE6667js9+9rM8++yznHvuuWy11VbceeedfOELX+CWW27pt9abbrqJvfbaq/r42WefZdKkSfzyl79kv/32q7avWrWKL33pS/ziF7/gmmuu4de//vXLch5++GFuvPFGrrzySmbNmlWt953vfCe33347n/nMZwDYe++9ueGGG+p9Kz2U0B9PV5SkzvLTn/6UW265hX322Qeo/PX+ute97hWvO+uss6oXKFq5ciX3338/2223HZttthkf/vCHAfjoRz/KUUcdBcDkyZP5yEc+wpFHHsmRRx4JwI9//GMWLFjAV7/6VQDWrl3Lgw8+yOLFiznppJOq202ePLnfWh9++GFe+9rXVh93dXVx9NFHv+J1v/rVr5g2bRqvec1rAPjQhz70sqWhjzzySDbbbDMmTpzII488MuB787rXvY5Vq5p6raG28HRFSVLdMpO/+qu/4itf+cqAr7n++uv5yU9+ws0338xWW23F/vvvz9q1a/t9bUTlCr9XXXUVixcvZsGCBXzpS19i2bJlZCaXX345u+6664DbDWbLLbd82X7HjBlDV1dXvz/TYGr/eB3stWvXrmXLLbfcYF1l56EESVLdDjzwQC677DIeffRRAJ588kl+97vfvew1q1ev5tWvfjVbbbUVv/71r/nFL35Rfe6ll16qHqe/+OKL2W+//XjppZdYuXIlBxxwAGeccQZPP/00a9as4ZBDDuEb3/hG9ZfxbbfdBlSWe15/+OLuu+8ecBnl3XbbjeXLl2/wZ5o6dSo/+9nPeOqpp1i3bh2XX375Brfpb0no3/zmN0yaNGmD2xacYyBJ6nwTJ07ky1/+Mu95z3uYPHkyBx98MA8//PDLXjN9+nTWrVvH5MmTOfnkk/mTP/mT6nPd3d0sW7aMvfbai2uvvZZTTjmF3t5ePvrRj/L2t7+dPfbYg8985jO86lWv4uSTT+bFF19k8uTJTJo0iZNPPhmAv/mbv2HNmjVMnjyZM844g6lTp/Zb66GHHsr111+/wZ9phx124B/+4R/Yd999Oeigg5g4cSJjxw5+tsfkyZOrS0uvn3x43XXXceihdS+D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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['total_ticks', 'elapsed']].plot.bar(\n", + " logy=True, secondary_y=['elapsed'], \n", + " figsize=(8, 6), title=\"Internal vs external time\")\n", + "plt.savefig('internal_external_time.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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OTIiNgUezMxX/SOLiFnURuwuKG4/DLy1GDwjSZK6qGV7zZn5d+CRiDgCVv/wxuhi9nzggGL6rtS+VvREq2qTJKmqmrZHHxG/APajNtr2MWqfYV4PnEPt0NkA4NLM/HpEjAD+L7WRsgl8KTOvaUphkiStR5p66F6SJPUuB7xJklRhNnpJkiqsKT+Ys8EGG+SgQYOaES1JUuk8//zzmZml3HluSqMfNGgQy5Yta0a0JEmlExEvrHup3lHKdx+SJKln2OglSaowG70kSRXWtLPXSZLW7uWXX2bhwoUsX768t0tRgwYOHMiwYcMYMGBAb5fSMBu9JPWShQsXsskmm7DjjjtSO+mgyiwzeeqpp1i4cCE77bRTb5fTMA/dS1IvWb58OVtuuaVNvo+ICLbccss+dwTGRi9Jvcgm37f0xefLRi9JUoX5Gb0klcSOk37bo3nzphyyzmWWLFnCJZdcwgknnNBxzrx5/OlPf+Koo45a+/bmzeN973sf999/f7vzZ86cyaJFi3jve98LwLRp05g9ezaTJk3qUp4a4x69JK3HlixZwtlnn73WZebNm8cll1zS7W3NnDmTq6++evXtD3zgAx02efUcG70krccmTZrE//7v/zJmzBhOOeUUTjnlFEaOHMmb3/xmpk6dunqZP/7xj4wZM4bvfe97zJs3j3e+853sscce7LHHHvzpT39a53ZeeuklTj/9dKZOncqYMWOYOnUqF1xwASeeeCIAjz32GIcddhijR49m9OjRr8p8+OGH2X333bnjjjuYNWsWY8eOZcyYMYwaNYq5c+f2/ANTIR66l6T12JQpU7j//vuZOXMmV155JT/+8Y+55557ePLJJ9l7773Zd999mTJlCt/5zneYPn06AM8//zzXXnstAwcOZO7cuRx55JHMmDFjrdvZcMMN+frXv86MGTP40Y9+BMAFF1ywev5JJ53EuHHj+NWvfsXKlStZunQpzzzzDAAPPvggEydO5Gc/+xljxozhc5/7HCeffDIf/ehHeemll1i5cmVzHpyKsNFLkgC4+eabOfLII+nXrx/bbLMN48aN44477mDTTTddY7mXX36ZE088kZkzZ9KvXz/+8pe/dHvb119/PT//+c8B6NevH0OHDuWZZ57hiSee4NBDD+XKK69kt912A+Btb3sbkydPZuHChXzwgx9k+PDh3d5+lXnoXpIE1H4QphHf+9732GabbbjnnnuYMWMGL730UtNqGjp0KDvssAO33HLL6mlHHXUU06ZNY9CgQYwfP57rr7++aduvAvfoJanJ2htNP2/gUexaP+GMZ1tWT71NNtmE5557DoB9992Xn/zkJxxzzDE8/fTT3HTTTXz729/m0UcfXb0MwLPPPsuwYcPYYIMNuPDCCxs+dF6/rbYOOOAAzjnnHD7/+c+zcuXK1ac633DDDfn1r3/N+PHjGTJkCEcddRQPP/wwO++8MyeddBIPP/ww9957L+9617u6+UhUl41ekkqika/D9bQtt9ySd7zjHYwcOZL3vOc9jBo1itGjRxMRnHnmmWy77bZsueWW9O/fn9GjR3PsscdywgkncPjhh3P55Zez//77M3jw4Ia2tf/++zNlyhTGjBnDqaeeusa8H/zgBxx//PGcd9559OvXj3POOYftttsOgMGDBzN9+nQOOuggBg8ezOzZs7nooosYMGAA2267LaeffnqPPy5VEo0equmMwYMH56p3Y5K0vutoj34NvbRHr86bM2cOu+66xvEYIuL5zGzsHU+L+Rm9JEkV5qF7SVKP+t3vfseXv/zlNabttNNO/OpXv+qlitZvNnpJUo8aP34848eP7+0yVPDQvSRJFWajlySpwmz0kiRVmI1ekvQqO+64I08++WTLt7vffvt1+Lv5H/rQh3j44YfbnfepT32K2bNnrzX72GOP5YorrnjV9LZn57vvvvs49thjGy+65ByMJ0llccbQHs6rznfzZ82axcqVK9l5551fNW/lypX89Kc/7XL2qkZ/1FG13zZ485vfzMKFC5k/fz6ve93rupxbFu7RS9J67KKLLlp9ytd//ud/bvfnbCdMmMCee+7Jbrvtxrnnnrt6+pAhQ/jiF7/IHnvswQEHHMATTzwBwFlnncWIESMYNWoUEydOBGDZsmV88pOfZO+992b33XfnqquuAuCFF15g4sSJjBo1io985CO88MIL7dZ58cUXc+ihh66x7dNPP523vOUt/PnPf17jSMB5553HLrvswn777cenP/3p1afCBbjpppt4+9vfzs4777x6777taXgB3v/+93PppZd2+XEtExu9JK2n5syZw9SpU7nllltWn4nu4osvftVy559/PnfeeSczZszgrLPO4qmnngJqzXuPPfbgrrvuYty4cXzta18Daqe+vfvuu7n33nv58Y9/DMDkyZN517vexR133MENN9zAKaecwrJlyzjnnHPYeOONuffee/nXf/1X7rzzznZrveWWW9hzzz1X3162bBkjR47ktttuY5999lk9fdGiRXzjG9/g1ltv5dprr+WBBx5YI2fx4sXcfPPNTJ8+nUmTJq2u953vfCczZ87kC1/4AgB77bUXf/zjH7v60JaKh+4laT113XXXceedd7L33nsDtb3rrbfe+lXLnXXWWat/7GbBggXMnTuXLbfckg022ICPfOQjABx99NF88IMfBGDUqFF89KMfZcKECUyYMAGAa665hmnTpvGd73wHgOXLlzN//nxuuukmTjrppNXrjRo1qt1aFy9ezFZbbbX6dr9+/Tj88MNftdztt9/OuHHj2GKLLQA44ogj1jiN7oQJE9hggw0YMWIEjz32WIePzdZbb82iRYs6nN+X2OglaT2VmRxzzDF861vf6nCZG2+8kd///vf8+c9/ZuONN2a//fZj+fLl7S4bEQD89re/5aabbmLatGl84xvfYNasWWQmV155JW984xs7XG9tBg0atMZ2Bw4cSL9+/dq9T2uz0UYbNbTs8uXLGTRo0Drr6gs8dC9J66kDDjiAK664gscffxyAp59+mr/+9a9rLPPss8+y+eabs/HGG/PAAw9w6623rp73yiuvrP6c+5JLLmGfffbhlVdeYcGCBey///6ceeaZLFmyhKVLlzJ+/Hh++MMfrm6ud999N1A7Ne6qjwvuv/9+7r333nZr3XXXXXnooYfWeZ/Gjh3LH/7wB5555hlWrFjBlVdeuc512jt97l/+8hdGjhy5znX7Ahu9JK2nRowYwTe/+U3e/e53M2rUKA466CAWL168xjIHH3wwK1asYNSoUZx22mm89a1vXT1v8ODBzJo1iz333JPrr7+e008/nZUrV3L00Ufz5je/md13350vfOELbLbZZpx22mm8/PLLjBo1ipEjR3LaaacB8JnPfIalS5cyatQozjzzTMaOHdturYcccgg33njjOu/T9ttvz1e+8hXe8pa3cOCBBzJixAiGDl37txlGjRq1+jS8qwbj3XDDDRxySOtPG9wMDZ+mNiL6ATOARzPzfWtb1tPUStI/VPU0tUOGDGHp0qUt2dYLL7zA/vvvzy233NLuIft6S5cuZciQIaxYsYLDDjuMT37ykxx22GENb+vFF19k3Lhx3Hzz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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['total_ticks', 'elapsed']].plot.bar(\n", + " logy=False, secondary_y=['elapsed'], \n", + " figsize=(8, 6), title=\"Internal vs external time\")\n", + "plt.savefig('internal_external_time_linear.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 179, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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8t/5Z6kMm3+1GHk4CjgqIt5drH4a8JVimP1/biRrIL5OZdLmKuAa4GcDzOlXMfQ/g8rchUeofBY/pDJ3YiBmApOofD9+DpxczKfor4bbgJeBuzJz2QC3KzVc1+xrSVKdRMQNwMWZ+cNm1yJVy4ZAkuqo2D1xHbB9jwmJUqm5y0CS6iQiLgCuB/4/mwG1GkcIJEmSIwSSJMmGQJIkUdITE40aNSo33XTTZpchSVLDvPDCC5mZTftDvVQNQUTMAGaMHTuW559/vtnlSJLUMBHx4sZfNYTbL+Okwvb29rQhkCSNJBHxQma2N2v7ziGQJEk2BJIkqWRzCPqzZs0aOjo6WL169cZfrFIZN24cEydOZPTo0c0uRZLUh5ZpCDo6Othiiy2YNGkSlQu3qRVkJitWrKCjo4PJkyc3uxxJUh9KtcsgImZExJy1aze8suvq1auZMGGCzUCLiQgmTJjgyI4klVypGoLMnJ+Zs9ra2np93magNfm5SVL5laohkCRJzdEycwh6mnTSNXXNWzb7Qxt9zcqVK7n44os57rjj+s5Ztozbb7+dww8/vP/tLVvGhz/8Ye6///7a6uy23k033cTpp5/O1VdfXVOGJEk9OUJQg5UrV/L973+/39csW7aMiy++uEEVSZKGkbaImFOctbfhbAhqcNJJJ/Ff//Vf7LrrrpxwwgmccMIJTJ06lZ133pl58+ate80tt9zCrrvuyne/+12WLVvGu9/9bnbffXd23313br/99qq2Vet6Tz31FIcccgjTpk1jr7324t577wXgueee46ijjmLnnXdm2rRpXHHFFYN7EyRJQ2VtZs7KzPnN2HjL7jJohtmzZ3P//fezZMkSrrjiCs4991zuuecennzySfbYYw/23XdfZs+evd4w/gsvvMB1113HuHHjePjhh5k5cyaLFy/e6LZe85rX1LTeySefzG677cYvfvELbrjhBo488kiWLFnCN77xDcaPH899990HwNNPP12fN0OSNKzYEAzQrbfeysyZM2lra+O1r30t++23H4sWLWLLLbdc73Vr1qzh+OOPZ8mSJbS1tfH73/++qvxa17v11lvX/fX/3ve+lxUrVrBq1Squv/56Lr300nWv22qrrWr8SSVJI0GpGoLuVzssu2ovCvXd736X1772tdxzzz28/PLLjBs3bkjW662eiCAzPexPreuU8b0sW9X4Okqgt4nU1UyGlqpVqjkEGzsPQbNtscUWPPvsswDsu+++zJs3j7Vr1/LEE0+wcOFC9txzz/VeA7Bq1Spe//rXM2rUKC666CJ6O+lSb2pdb9999+UnP/kJADfddBNbb701W265JR/4wAc4++yz173OXQaSpN6UaoSgFs3ojCdMmMA+++zD1KlTOeigg5g2bRq77LILEcG3v/1tXve61zFhwgQ22WQTdtllFz75yU9y3HHHceihh3L55Zfznve8h/b26q5sWet6p5xyCkcddRTTpk1js80244ILLgDgK1/5Cv/8z//M1KlTaWtr4+STT+ajH/3ooN8LSdLwEtUOfTdSe3t7Pv/88+ste/DBB9lxxx2bVJEGy89PA+Iug3XcZTD8RcQLmVndX41DoFS7DCRJUnO07C6D4eLaa6/lxBNPXG/Z5MmT+fnPf96kiiRJI5ENQZMdeOCBHHjggc0uQ5I0wrnLQJIk2RBIkqQh2mUQEW8CvgyMz8yPFcsOAT4EvAY4JzN/NRTblqQRo+dRGCP0CAzVR9UjBBFxXkQ8HhH391g+PSIeioilEXESQGb+ITOP7v66zPxFZh4LfBL4hzrUriqcccYZXHjhhb0+d+655/b5XJe5c+dy/PHH9/rcN7/5zXX3X3rpJfbdd186OzsHXqwkqWlqGSGYC5wNrPsNEhFtwDnA+4EOYFFEXJWZv+0n5yvFOoPT2/HJg8prnc66s7OTTTbZ+EfX2dnJeeedx1133dXrc5/+9KcHVcc3v/lNvvSlLwEwZswYDjjgAObNm8cRRxwxqFxJUuNVPUKQmQuBp3os3hNYWowIvARcChzc2/pR8S3gl5m54W+oklu2bBlvectbOOaYY5g6dSpHHHEE119/Pfvssw9TpkzhzjvvBOD555/nU5/6FHvssQe77bYbV155JVD5S/uQQw5hxowZTJ48mbPPPpvvfOc77Lbbbuy111489VTlrV2yZAl77bUX06ZN4yMf+ci6Uw3vv//+fOlLX2K//fbj1FNPZfLkyaxZswaAZ555hkmTJq173OWGG25g9913X9c8dM8488wzOeWUUzj99NMBWLRoEdOmTWPvvfded1nnLo899hjTp09nypQpfOELXwAql3l+8cUX2XXXXdc1AIcccsi60ydLklrLYCcVbgcs7/a4A9guIiZExLnAbhHxxeK5fwHeB3wsIjb40zQiZkXE4ohYXNZh56VLl/K5z32Oe++9l9/97ndcfPHF3HrrrZx++unrhs9PPfVU3vve97Jo0SJuvPFGTjjhBLrOunj//fdz8cUXc+edd/LlL3+ZzTbbjLvvvpu999573dD9kUceybe+9S3uvfdedt55Z77+9a+v2/7KlSu5+eabOfnkk9l///255prKmcsuvfRSDj30UEaPHr1evbfddhtve9vb1lvWlfH5z39+veVHHXUU5557LnfccQc9ryWxZMkS5s2bx3333ce8efNYvnw5s2fPZtNNN2XJkiXrmoCpU6eyaNGiwb7NkqQmGGxD0Ntl9DIzV2TmpzPzbzLztGLh9zLzbcXyc3tZaU5mvj0z317NcHgzTJ48mZ133plRo0bx1re+lQMOOICIYOedd2bZsmUA/OpXv2L27Nnsuuuu7L///qxevZo//elPALznPe9hiy22YJtttmH8+PHMmDEDYN36q1atYuXKley3334AfOITn2DhwoXrtv8P//DK1ItjjjmG888/H4Dzzz+fo446aoN6//znP7PNNtust6x7RpeVK1fy7LPP8s53vhOAww8/fL3nDzjgAMaPH8+4cePYaaed+OMf/9jr+9PW1saYMWPWu7iTJKk1DPY3bwewfbfHE4HHBhpW9ssfd69r1KhR6x6PGjVq3WS6zOSKK65ghx12WG/d3/zmN1Wt35/uFzjaZ599WLZsGTfffDNr165db4i/y6abbsrq1av7zOiysetZdK+7ra2t31r/+te/Vn2JZ0lSeQx2hGARMCUiJkfEGOAw4KqBhpX98sfVOPDAAznrrLPW/ZK9++67q153/PjxbLXVVtxyyy0AXHTRRetGC3pz5JFHMnPmzF5HBwB23HFHli5dutHtbrXVVmyxxRb8+te/Biq7IKoxevTo9eYtrFixgm222WaDXReSpPKr5bDDS4A7gB0ioiMijs7MTuB44FrgQeCyzHxgaEptDV/96ldZs2YN06ZNY+rUqXz1q1+taf0LLriAE044gWnTprFkyRK+9rWv9fnaI444gqeffpqZM2f2+vxBBx203i6H/vzoRz9i1qxZ7L333mQm48dv/CiOWbNmMW3atHWTCm+88UY++MEPVrU9SVK5lOryx912GRzbc6jby+du6Kc//SlXXnklF110UZ+v+chHPsK3v/1tpkyZ0m/Wc889x+abbw7A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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['total_alloc', 'memory']].plot.bar(\n", + " logy=True, secondary_y=['memory'], \n", + " figsize=(8, 6), title=\"Internal vs external memory\")\n", + "plt.savefig('internal_external_memory_log.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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9P7yZ1HskqCnp2fIenY+6dIhl2nFstl/Puj8VatWsWDBAj7+8Y8PnLFsGTfffDMf+MAHBt/WsmW8+93v5p577mmtxob1rr32Wr72ta9xySWXtJQhSdJQmho5iIgxFI3B9zPzh/0sshx4fcPjCcCKQaa/TGbOzcxpmTlt9Oj6/Yhi1apVnHXWWYMus2zZMhYsWNCmiiRJGhlDNgflLxH+HbgvM78+wGIXA8dGYW9gdWY+DCwGJkXExIjoAY4ul+06J510Ev/93//N1KlTOfHEEznxxBOZPHkyu+22GwsXLly3zA033MDUqVP5xje+wbJly3j729/OnnvuyZ577snNN9/c1LZaXe/xxx/nyCOPZMqUKey9997cddddADz99NMcd9xx7LbbbkyZMoULLrhgw54ESdIrQjNf0fcFPgjcHRFLymmfAd4AkJlzgEUUP2NcSvFTxuPKeWsj4gTgcoqfMs7LzHuH8w9ol9mzZ3PPPfewZMkSLrjgAubMmcOdd97JY489xl577cV+++3H7NmzK0P9zz77LFdeeSVjx47lV7/6FTNnzuS2224bclvbbbddS+udcsop7LHHHvzoRz/i6quv5thjj2XJkiV84QtfYPz48dx9990APPHEE8PzZEiSNmpDNgeZeSP9HzvQuEwCnxhg3iKK5mGjceONNzJz5kxGjRrF9ttvz/7778/ixYvZcsstK8u98MILnHDCCSxZsoRRo0bxy1/+sqn8Vte78cYb140KvOMd72DlypWsXr2aq666ivPOO2/dcltttVWLf6kk6ZWofjv3u0DRCw3tG9/4Bttvvz133nknL730EmPHjh2R9fqrJyLITH9KKElqmddWaNK4ceN46qmnANhvv/1YuHAhL774Io8++ijXX38906dPrywDsHr1al772teyySabcM455/Diiy82ta1W19tvv/34/ve/D8C1117LNttsw5ZbbsnBBx/MmWeeuW45dyuoq5w6/uW3V6idT7r0ZTdpJHXtyMFQPz0cbltvvTX77rsvkydP5tBDD2XKlCnsvvvuRARf+cpX2GGHHdh6660ZPXo0u+++Ox/60If4+Mc/zlFHHcX555/PgQceyOabb97Utlpd79RTT+W4445jypQpbLbZZnzve98D4HOf+xyf+MQnmDx5MqNGjeKUU07hve997wY/F5KkjVs0O0TeTptvvnk+88wzlWn33Xcfu+yyS4cq0obwtdN66W+k4NTV7a+jBvobKWj3FySNrIh4NjOb+wbZBu5WkCRJFV27W2FjcPnll/PpT3+6Mm3ixIlceOGFHapIkiSbg4465JBDOOSQQzpdhiRJFTYHkiTVXETMA94NPJKZk/uZfyJwTPlwNLALsG1mPh4Ry4CngBeBtZk5bajtecyBJEn1Nx+YMdDMzPxqZk7NzKnAPwLXZebjDYscWM4fsjEAmwNJkmovM68HHh9ywcJM4NwN2Z7NwUbu9NNP5+yzz+533pw5cwac12v+/PmccMIJ/c770pe+tO7+888/z3777cfatWvXv1hJ0gaJiM0oRhgar7SXwBUR8bOImNVMTvceczDcZ0vrot9Pr127lmYua7127VrmzZvH7bff3u+8j370oxtUx5e+9CU+85nPANDT08NBBx3EwoULOeaYY4ZYU5LUx+iIaLzC3tzMnLseOYcDN/XZpbBvZq6IiO2AKyPi/nIkYkCOHDRp2bJlvPnNb+b4449n8uTJHHPMMVx11VXsu+++TJo0iVtvvRWAZ555hr/5m79hr732Yo899uCiiy4Cim/gRx55JIcffjgTJ07kzDPP5Otf/zp77LEHe++9N48/XryOS5YsYe+992bKlCm85z3vWXfK4wMOOIDPfOYz7L///nzxi19k4sSJvPDCCwA8+eST7Lzzzuse97r66qvZc8891zUSjRlnnHEGp556Kl/72tcAWLx4MVOmTGGfffZZdznqXitWrGDGjBlMmjSJf/iHfwCKy1M/99xzTJ06dV0zcOSRR647jbMkqSVrM3Naw219GgOAo+mzSyEzV5T/PgJcCEwfKsTmoAVLly7lk5/8JHfddRf3338/CxYs4MYbb+RrX/vauiH2L37xi7zjHe9g8eLFXHPNNZx44on0nu3xnnvuYcGCBdx666189rOfZbPNNuOOO+5gn332WTe8f+yxx/LlL3+Zu+66i912241/+qd/Wrf9VatWcd1113HKKadwwAEHcOmlxVnTzjvvPI466ijGjBlTqfemm27irW99a2Vab8anPvWpyvTjjjuOOXPm8JOf/IRRo0ZV5i1ZsoSFCxdy9913s3DhQh566CFmz57NpptuypIlS9Y1BJMnT2bx4sUb+jRLktZDRIwH9gcuapi2eUSM670PHAzcM1SWzUELJk6cyG677cYmm2zCW97yFg466CAigt12241ly5YBcMUVVzB79mymTp3KAQccwJo1a/jNb34DwIEHHsi4cePYdtttGT9+PIcffjjAuvVXr17NqlWr2H///QH467/+a66//g8jP3/5l3+57v7xxx/Pd7/7XQC++93vctxxx72s3ocffphtt922Mq0xo9eqVat46qmn+LM/+zMAPvCBD1TmH3TQQYwfP56xY8ey66678utf/7rf52fUqFH09PRULj4lSdpwEXEu8BPgTRGxPCI+HBEfjYjG/cPvAa7IzMbrD2wP3BgRdwK3Apdm5o+H2l73HnPQAa961avW3d9kk03WPd5kk03WHYiXmVxwwQW86U1vqqz705/+tKn1B9N4AaZ9992XZcuWcd111/Hiiy9WdgP02nTTTVmzZs2AGb2Gur5GY92jRo0atNbf//73TV+aWpLUnMyc2cQy8yl+8tg47QFg91a358jBMDvkkEP45je/ue4D94477mh63fHjx7PVVltxww03AHDOOeesG0Xoz7HHHsvMmTP7HTUA2GWXXVi6dOmQ291qq60YN24ct9xyC1DspmjGmDFjKsc5rFy5km233fZluzckSd3F5mCYff7zn+eFF15gypQpTJ48mc9//vMtrf+9732PE088kSlTprBkyRJOPvnkAZc95phjeOKJJ5g5s/+G8tBDD63slhjMv//7vzNr1iz22WcfMpPx44f+NcisWbOYMmXKugMSr7nmGg477LCmtidJqi8v2dzFfvCDH3DRRRdxzjnnDLjMe97zHr7yla8wadKkQbOefvpptthiCwBmz57Nww8/zBlnnNFSPe9973s57bTTXrZLxddO68VLNq/jJZs3fnW7ZLPHHHSpv/3bv+Wyyy5j0aJFgy7X+0E/VHNw6aWXctppp7F27Vp22mkn5s+f31I9zz//PEceeeTLGgNJUvdx5EAjztdO68WRg3UcOdj41W3kwGMOJElSRVc1B3Uc5dDgfM0kqft0TXMwduxYVq5c6YdNF8lMVq5c6XkPJKnLdM0BiRMmTGD58uU8+uijnS5FLRg7diwTJkzodBmSpBZ0TXMwZswYJk6c2OkyJEna6HXNbgVJktQeNgeSJKnC5kCSJFXYHEiSpAqbA0mSVDHkrxUiYh7wbuCRzJzcz/wTgWMa8nYBts3MxyNiGfAU8CKwNjOnDVfhkiRpZDQzcjAf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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# performance[['total_ticks', 'elapsed']].plot.bar(logy=True)\n", + "performance[['total_alloc', 'memory']].plot.bar(\n", + " logy=False, secondary_y=['memory'], \n", + " figsize=(8, 6), title=\"Internal vs external memory\")\n", + "plt.savefig('internal_external_memory_linear.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 181, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "# performance['elapsed_adj'] = performance['elapsed'] - 0.28\n", + "# performance" + ] + }, + { + "cell_type": "code", + "execution_count": 182, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "# performance[['total_time', 'elapsed_adj']].plot.bar(logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(ncols=3, figsize=(20,5))\n", + "\n", + "performance['elapsed'].plot.bar(ax=ax[2],\n", + " logy=True, \n", + " title=\"Run times (wall clock), log scale\",\n", + "# figsize=(10,8)\n", + " )\n", + "ax[2].set_xlabel('Program')\n", + "\n", + "performance['elapsed'].plot.bar(ax=ax[0],\n", + " logy=False, \n", + " title=\"Run times (wall clock), linear scale\",\n", + "# figsize=(10,8)\n", + " )\n", + "ax[0].set_xlabel('Program')\n", + "\n", + "performance['elapsed'].plot.bar(ax=ax[1],\n", + " logy=False, \n", + " ylim=(0, 22),\n", + " title=\"Run times (wall clock), truncated linear scale\",\n", + "# figsize=(10,8)\n", + " )\n", + "ax[1].set_xlabel('Program')\n", + "\n", + "plt.savefig('run_times_combined.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 184, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(ncols=2, figsize=(13,5))\n", + "\n", + "performance['memory'].plot.bar(ax=ax[0],\n", + " logy=True, \n", + " title=\"Memory used, log scale\",\n", + "# figsize=(10,8)\n", + " )\n", + "ax[0].set_xlabel('Program')\n", + "\n", + "performance['memory'].plot.bar(ax=ax[1],\n", + " logy=False, \n", + " title=\"Memory used, linear scale\",\n", + "# figsize=(10,8)\n", + " )\n", + "ax[1].set_xlabel('Program')\n", + "\n", + "plt.savefig('memory_combined.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 251, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(ncols=2, figsize=(13,5))\n", + "\n", + "performance[['total_alloc', 'memory']].plot.bar(ax=ax[0],\n", + " logy=False, secondary_y=['memory'], \n", + " title=\"Internal vs external memory, linear scale\")\n", + "ax[0].set_xlabel('Program')\n", + "\n", + "performance[['total_alloc', 'memory']].plot.bar(ax=ax[1],\n", + " logy=True, secondary_y=['memory'], \n", + " title=\"Internal vs external memory. log scale\")\n", + "\n", + "plt.savefig('internal_external_memory_combined.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 185, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "# ax = performance['elapsed_adj'].plot.bar(logy=False, \n", + "# title=\"Run times (wall clock), linear scale\",\n", + "# figsize=(10,8))\n", + "# ax.set_xlabel('Program')\n", + "# plt.savefig('run_times_linear.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 186, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['total_time', 'total_alloc', 'total_ticks', 'initial_capabilities',\n", + " 'system', 'elapsed', 'memory'],\n", + " dtype='object')" + ] + }, + "execution_count": 186, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "performance.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 187, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 187, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance['memory'].plot.bar()" + ] + }, + { + "cell_type": "code", + "execution_count": 188, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 188, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.plot.scatter('elapsed', 'total_alloc', logx=True, logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 189, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 189, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.plot.scatter('memory', 'total_alloc', logx=True, logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 190, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "performance.plot.scatter('elapsed', 'total_ticks', logx=True, logy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 191, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "performance[['total_alloc', 'memory', 'elapsed']].to_csv('performance.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 192, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "| program | total_alloc | elapsed | memory |\n", + "|:----------|--------------:|----------:|---------:|\n", + "| advent01 | 11516576 | 0.02 | 10488 |\n", + "| advent02 | 9613016 | 0.02 | 11112 |\n", + "| advent03 | 6018112 | 0.02 | 10408 |\n", + "| advent04 | 2913824 | 0.01 | 9040 |\n", + "| advent05 | 3396888 | 0.01 | 9324 |\n", + "| advent06 | 5025888 | 0.02 | 10124 |\n", + "| advent07 | 3049136 | 0.01 | 9192 |\n", + "| advent08 | 214597512 | 0.09 | 12204 |\n", + "| advent09 | 39708256 | 0.06 | 23660 |\n", + "| advent10 | 631808 | 0.01 | 6800 |\n", + "| advent11 | 655812832 | 0.36 | 66664 |\n", + "| advent12 | 1598902400 | 1.09 | 13264 |\n", + "| advent13 | 10281760 | 0.01 | 12300 |\n", + "| advent14 | 258169680 | 0.85 | 15068 |\n", + "| advent15 | 126607950592 | 137.27 | 18101260 |\n", + "| advent16 | 296137053800 | 144.64 | 45628 |\n", + "| advent17 | 77649009464 | 20.67 | 22000 |\n", + "| advent18 | 68244096 | 0.06 | 14060 |\n", + "| advent19 | 1964531122296 | 1134.12 | 14295324 |\n", + "| advent20 | 55860434768 | 15.04 | 13940 |\n", + "| advent21 | 351135824 | 0.40 | 12680 |\n", + "| advent22 | 528445105288 | 0.23 | 15908 |\n", + "| advent23 | 26387446504 | 370.18 | 13628 |\n", + "| advent24 | 3268072336 | 2.74 | 74820 |\n", + "| advent25 | 642496 | 0.01 | 5896 |\n" + ] + } + ], + "source": [ + "print(performance[['total_alloc', 'elapsed', 'memory']].to_markdown(floatfmt=['0.0f', '0.0f', '.2f', '0.0f']))" + ] + }, + { + "cell_type": "code", + "execution_count": 232, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "advent01 22\n", + "advent02 93\n", + "advent03 51\n", + "advent04 57\n", + "advent05 105\n", + "advent06 30\n", + "advent07 137\n", + "advent08 76\n", + "advent09 97\n", + "advent10 76\n", + "advent11 148\n", + "advent12 155\n", + "advent13 61\n", + "advent14 107\n", + "advent15 91\n", + "advent16 274\n", + "advent17 171\n", + "advent18 72\n", + "advent19 221\n", + "advent20 56\n", + "advent21 118\n", + "advent22 269\n", + "advent23 215\n", + "advent24 224\n", + "advent25 52\n", + "dtype: int64" + ] + }, + "execution_count": 232, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line_counts = ! find .. -path ../dist-newstyle -prune -o -type f -name \"Main.hs\" -exec wc -l {} \\;\n", + "count_names = [re.search(\"(\\d+) \\.\\./([^/]+)\", l).groups([2, 1]) for l in line_counts if 'advent' in l if 'Main' in l]\n", + "program_counts = pd.Series({n: int(c) for n, c in sorted([(c, n) for n, c in count_names])})\n", + "program_counts" + ] + }, + { + "cell_type": "code", + "execution_count": 243, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "program_counts[::-1].plot.barh(figsize=(6, 9))\n", + "plt.savefig('lines_of_code.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "| | 0 |\n", + "|:---------|----:|\n", + "| advent01 | 22 |\n", + "| advent02 | 93 |\n", + "| advent03 | 51 |\n", + "| advent04 | 57 |\n", + "| advent05 | 105 |\n", + "| advent06 | 30 |\n", + "| advent07 | 137 |\n", + "| advent08 | 76 |\n", + "| advent09 | 97 |\n", + "| advent10 | 76 |\n", + "| advent11 | 148 |\n", + "| advent12 | 155 |\n", + "| advent13 | 61 |\n", + "| advent14 | 107 |\n", + "| advent15 | 91 |\n", + "| advent16 | 274 |\n", + "| advent17 | 171 |\n", + "| advent18 | 72 |\n", + "| advent19 | 221 |\n", + "| advent20 | 56 |\n", + "| advent21 | 118 |\n", + "| advent22 | 269 |\n", + "| advent23 | 215 |\n", + "| advent24 | 224 |\n", + "| advent25 | 52 |\n" + ] + } + ], + "source": [ + "print(program_counts.to_markdown())" + ] + }, + { + "cell_type": "code", + "execution_count": 245, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "97.0" + ] + }, + "execution_count": 245, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "program_counts.median()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,md" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/profiling/profiling.md b/profiling/profiling.md new file mode 100644 index 0000000..88811ae --- /dev/null +++ b/profiling/profiling.md @@ -0,0 +1,360 @@ +--- +jupyter: + jupytext: + formats: ipynb,md + text_representation: + extension: .md + format_name: markdown + format_version: '1.3' + jupytext_version: 1.11.1 + kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +```python Collapsed="false" +import glob +import json +import pandas as pd +import numpy as np +import datetime +import re + +import matplotlib.pyplot as plt +%matplotlib inline +``` + +```python +! cd .. && cabal install +``` + +```python Collapsed="false" tags=[] +! cd .. && for i in {01..25}; do cabal run advent${i} --enable-profiling -- +RTS -N -pj -s -hT ; done +``` + +```python +! rm ../times.csv +! rm ../times_raw.csv +``` + +```python Collapsed="false" tags=[] +! cd .. && for i in {01..25}; do /usr/bin/time -f "%C,%S,%E,%M" -o times.csv -a cabal run advent${i}; done +``` + +```python Collapsed="false" tags=[] +! cd .. && for i in {01..25}; do /usr/bin/time -f "%C,%S,%E,%M" -o times_raw.csv -a advent${i}; done +``` + +```python +!mv ../*prof . +``` + +```python +!mv ../times.csv . +``` + +```python +!mv ../times_raw.csv . +``` + +```python +!mv ../*hp . +``` + +```python +! for f in *hp ; do hp2ps ${f} ; done +``` + +```python Collapsed="false" +glob.glob('*prof') +``` + +```python Collapsed="false" +profs = [] +for fn in glob.glob('*prof'): + with open(fn) as f: + j = json.load(f) + prof = {} + for n in 'program total_time total_alloc total_ticks initial_capabilities'.split(): + prof[n] = j[n] + profs.append(prof) +profs +``` + +```python Collapsed="false" +performance = pd.DataFrame(profs).set_index('program').sort_index() +performance +``` + +```python Collapsed="false" +performance.total_ticks.plot.bar() +``` + +```python Collapsed="false" +performance.total_ticks.plot.bar(logy=True) +``` + +```python Collapsed="false" +performance.total_alloc.plot.bar() +``` + +```python Collapsed="false" +performance.total_alloc.plot.bar(logy=True) +``` + +```python Collapsed="false" +performance[['total_ticks', 'total_alloc']].plot.bar( + logy=True, secondary_y=['total_alloc'], + figsize=(8, 6), title="Internal time and memory") +plt.savefig('internal_time_and_memory_log.png') +``` + +```python Collapsed="false" +performance[['total_ticks', 'total_alloc']].plot.bar( + logy=False, secondary_y=['total_alloc'], + figsize=(8, 6), title="Internal time and memory") +plt.savefig('internal_time_and_memory_linear.png') +``` + +```python +# times = pd.read_csv('times.csv', +# names=['program', 'system', 'elapsed', 'memory'], +# index_col='program') +# times.index = times.index.str.slice(start=len('cabal run ')) +# times.elapsed = pd.to_numeric(times.elapsed.str.slice(start=2)) +# times +``` + +```python +today = datetime.date.today() +today = datetime.datetime(year=today.year, month=today.month, day=today.day) - datetime.timedelta(seconds=1) +today +``` + +```python +epoch = datetime.datetime(year=1900, month=1, day=1) +epoch +``` + +```python +times = pd.read_csv('times_raw.csv', + names=['program', 'system', 'elapsed', 'memory'], + index_col='program') +times.elapsed = (pd.to_datetime(times.elapsed, format="%M:%S.%f") - epoch) +times.elapsed = times.elapsed.apply(lambda x: x.total_seconds()) +times +``` + +```python +times.dtypes +``` + +```python Collapsed="false" +times.describe() +``` + +```python Collapsed="false" +performance = performance.merge(times, left_index=True, right_index=True) +# performance.drop(index='advent15loop', inplace=True) +performance +``` + +```python Collapsed="false" +performance.columns +``` + +```python +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance.elapsed.plot.bar( + figsize=(8, 6), title="External time") +plt.savefig('external_time.png') +``` + +```python +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['elapsed', 'memory']].plot.bar( + logy=False, secondary_y=['memory'], + figsize=(8, 6), title="External time and memory") +plt.savefig('external_time_and_memory.png') +``` + +```python +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['elapsed', 'memory']].plot.bar( + logy=True, secondary_y=['memory'], + figsize=(8, 6), title="External time and memory") +plt.savefig('external_time_and_memory_log.png') +``` + +```python Collapsed="false" +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['elapsed', 'memory']].plot.bar( + logy=False, secondary_y=['memory'], + figsize=(8, 6), title="External time and memory") +plt.savefig('external_time_and_memory_linear.png') +``` + +```python Collapsed="false" +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['total_ticks', 'elapsed']].plot.bar( + logy=True, secondary_y=['elapsed'], + figsize=(8, 6), title="Internal vs external time") +plt.savefig('internal_external_time.png') +``` + +```python Collapsed="false" +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['total_ticks', 'elapsed']].plot.bar( + logy=False, secondary_y=['elapsed'], + figsize=(8, 6), title="Internal vs external time") +plt.savefig('internal_external_time_linear.png') +``` + +```python Collapsed="false" +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['total_alloc', 'memory']].plot.bar( + logy=True, secondary_y=['memory'], + figsize=(8, 6), title="Internal vs external memory") +plt.savefig('internal_external_memory_log.png') +``` + +```python Collapsed="false" +# performance[['total_ticks', 'elapsed']].plot.bar(logy=True) +performance[['total_alloc', 'memory']].plot.bar( + logy=False, secondary_y=['memory'], + figsize=(8, 6), title="Internal vs external memory") +plt.savefig('internal_external_memory_linear.png') +``` + +```python Collapsed="false" +# performance['elapsed_adj'] = performance['elapsed'] - 0.28 +# performance +``` + +```python Collapsed="false" +# performance[['total_time', 'elapsed_adj']].plot.bar(logy=True) +``` + +```python Collapsed="false" +fig, ax = plt.subplots(ncols=3, figsize=(20,5)) + +performance['elapsed'].plot.bar(ax=ax[2], + logy=True, + title="Run times (wall clock), log scale", +# figsize=(10,8) + ) +ax[2].set_xlabel('Program') + +performance['elapsed'].plot.bar(ax=ax[0], + logy=False, + title="Run times (wall clock), linear scale", +# figsize=(10,8) + ) +ax[0].set_xlabel('Program') + +performance['elapsed'].plot.bar(ax=ax[1], + logy=False, + ylim=(0, 22), + title="Run times (wall clock), truncated linear scale", +# figsize=(10,8) + ) +ax[1].set_xlabel('Program') + +plt.savefig('run_times_combined.png') +``` + +```python Collapsed="false" +fig, ax = plt.subplots(ncols=2, figsize=(13,5)) + +performance['memory'].plot.bar(ax=ax[0], + logy=True, + title="Memory used, log scale", +# figsize=(10,8) + ) +ax[0].set_xlabel('Program') + +performance['memory'].plot.bar(ax=ax[1], + logy=False, + title="Memory used, linear scale", +# figsize=(10,8) + ) +ax[1].set_xlabel('Program') + +plt.savefig('memory_combined.png') +``` + +```python +fig, ax = plt.subplots(ncols=2, figsize=(13,5)) + +performance[['total_alloc', 'memory']].plot.bar(ax=ax[0], + logy=False, secondary_y=['memory'], + title="Internal vs external memory, linear scale") +ax[0].set_xlabel('Program') + +performance[['total_alloc', 'memory']].plot.bar(ax=ax[1], + logy=True, secondary_y=['memory'], + title="Internal vs external memory. log scale") + +plt.savefig('internal_external_memory_combined.png') +``` + +```python Collapsed="false" +# ax = performance['elapsed_adj'].plot.bar(logy=False, +# title="Run times (wall clock), linear scale", +# figsize=(10,8)) +# ax.set_xlabel('Program') +# plt.savefig('run_times_linear.png') +``` + +```python Collapsed="false" +performance.columns +``` + +```python Collapsed="false" +performance['memory'].plot.bar() +``` + +```python Collapsed="false" +performance.plot.scatter('elapsed', 'total_alloc', logx=True, logy=True) +``` + +```python Collapsed="false" +performance.plot.scatter('memory', 'total_alloc', logx=True, logy=True) +``` + +```python Collapsed="false" +performance.plot.scatter('elapsed', 'total_ticks', logx=True, logy=True) +``` + +```python Collapsed="false" +performance[['total_alloc', 'memory', 'elapsed']].to_csv('performance.csv') +``` + +```python Collapsed="false" +print(performance[['total_alloc', 'elapsed', 'memory']].to_markdown(floatfmt=['0.0f', '0.0f', '.2f', '0.0f'])) +``` + +```python +line_counts = ! find .. -path ../dist-newstyle -prune -o -type f -name "Main.hs" -exec wc -l {} \; +count_names = [re.search("(\d+) \.\./([^/]+)", l).groups([2, 1]) for l in line_counts if 'advent' in l if 'Main' in l] +program_counts = pd.Series({n: int(c) for n, c in sorted([(c, n) for n, c in count_names])}) +program_counts +``` + +```python +program_counts[::-1].plot.barh(figsize=(6, 9)) +plt.savefig('lines_of_code.png') +``` + +```python +print(program_counts.to_markdown()) +``` + +```python +program_counts.median() +``` + +```python + +``` diff --git a/profiling/run_times_combined.png b/profiling/run_times_combined.png new file mode 100644 index 0000000000000000000000000000000000000000..f834de7dd6d6a8d5ef14a425da1973659ea474ae GIT binary patch literal 17536 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 To&x_j5FEV6Vt4i~r=R{09@`s% literal 0 HcmV?d00001 diff --git a/profiling/run_times_linear.png b/profiling/run_times_linear.png new file mode 100644 index 0000000000000000000000000000000000000000..407fee4c839a7a8e71f902761e2c8e47692879ef GIT binary patch literal 10494 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 literal 0 HcmV?d00001 diff --git a/profiling/run_times_log.png b/profiling/run_times_log.png new file mode 100644 index 0000000000000000000000000000000000000000..2098debecd5f00f01fff7a175ca192564b4bc0a3 GIT binary patch literal 14648 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 literal 0 HcmV?d00001 diff --git a/profiling/time-results.csv b/profiling/time-results.csv new file mode 100644 index 0000000..04e90b6 --- /dev/null +++ b/profiling/time-results.csv @@ -0,0 +1,27 @@ +Program,Elapsed time (s),Max memory +advent01, 00.39, 72440 +advent02, 00.41, 72440 +advent03, 00.37, 72504 +advent04, 00.43, 72504 +advent05, 00.43, 72440 +advent06, 00.41, 72504 +advent07, 00.39, 72444 +advent08, 00.44, 72508 +advent09, 00.66, 72508 +advent10, 00.36, 72444 +advent11, 16.75, 72504 +advent12, 00.38, 72508 +advent13, 00.36, 72436 +advent14, 00.61, 72508 +advent15, 02.15, 240372 +advent15loop, 01.88, 240444 +advent16, 00.38, 72444 +advent17, 01.77, 72444 +advent18, 00.39, 72444 +advent19, 00.46, 72504 +advent20, 04.12, 72436 +advent21, 00.39, 72508 +advent22, 02.02, 72500 +advent23, 01.91, 95500 +advent24, 03.48, 72504 +advent25, 00.41, 72504 diff --git a/profiling/time-results.md b/profiling/time-results.md new file mode 100644 index 0000000..70c50c0 --- /dev/null +++ b/profiling/time-results.md @@ -0,0 +1,27 @@ +| Program | Elapsed time (mm:ss) | Max memory | +| advent01 | 0:00.39 | 72440 | +| advent02 | 0:00.41 | 72440 | +| advent03 | 0:00.37 | 72504 | +| advent04 | 0:00.43 | 72504 | +| advent05 | 0:00.43 | 72440 | +| advent06 | 0:00.41 | 72504 | +| advent07 | 0:00.39 | 72444 | +| advent08 | 0:00.44 | 72508 | +| advent09 | 0:00.66 | 72508 | +| advent10 | 0:00.36 | 72444 | +| advent11 | 0:16.75 | 72504 | +| advent12 | 0:00.38 | 72508 | +| advent13 | 0:00.36 | 72436 | +| advent14 | 0:00.61 | 72508 | +| advent15 | 0:02.15 | 240372 | +| advent15loop | 0:01.88 | 240444 | +| advent16 | 0:00.38 | 72444 | +| advent17 | 0:01.77 | 72444 | +| advent18 | 0:00.39 | 72444 | +| advent19 | 0:00.46 | 72504 | +| advent20 | 0:04.12 | 72436 | +| advent21 | 0:00.39 | 72508 | +| advent22 | 0:02.02 | 72500 | +| advent23 | 0:01.91 | 95500 | +| advent24 | 0:03.48 | 72504 | +| advent25 | 0:00.41 | 72504 | diff --git a/profiling/times.csv b/profiling/times.csv new file mode 100644 index 0000000..89d3e47 --- /dev/null +++ b/profiling/times.csv @@ -0,0 +1,25 @@ +cabal run advent01,0.03,0:00.35,81704 +cabal run advent02,0.03,0:00.28,81708 +cabal run advent03,0.03,0:00.29,81712 +cabal run advent04,0.03,0:00.28,81212 +cabal run advent05,0.03,0:00.29,81708 +cabal run advent06,0.03,0:00.33,81700 +cabal run advent07,0.04,0:00.33,81704 +cabal run advent08,0.07,0:00.35,81216 +cabal run advent09,0.02,0:00.34,81708 +cabal run advent10,0.03,0:00.27,81700 +cabal run advent11,0.13,0:00.71,81712 +cabal run advent12,0.14,0:01.16,81708 +cabal run advent13,0.04,0:00.27,81212 +cabal run advent14,0.04,0:01.18,81708 +cabal run advent15,19.38,2:13.30,18018836 +cabal run advent16,16.38,2:26.46,81704 +cabal run advent17,4.27,0:21.79,81220 +cabal run advent18,0.05,0:00.36,81712 +cabal run advent19,86.14,19:05.60,15398736 +cabal run advent20,3.22,0:18.54,210392 +cabal run advent21,0.34,0:03.20,271008 +cabal run advent22,0.05,0:00.49,81712 +cabal run advent23,2.61,6:20.63,331416 +cabal run advent24,0.63,0:07.22,331760 +cabal run advent25,0.43,0:01.86,144388 diff --git a/profiling/times_raw.csv b/profiling/times_raw.csv new file mode 100644 index 0000000..5247c14 --- /dev/null +++ b/profiling/times_raw.csv @@ -0,0 +1,25 @@ +advent01,0.00,0:00.02,10488 +advent02,0.00,0:00.02,11112 +advent03,0.00,0:00.02,10408 +advent04,0.00,0:00.01,9040 +advent05,0.01,0:00.01,9324 +advent06,0.01,0:00.02,10124 +advent07,0.00,0:00.01,9192 +advent08,0.02,0:00.09,12204 +advent09,0.01,0:00.06,23660 +advent10,0.00,0:00.01,6800 +advent11,0.07,0:00.36,66664 +advent12,0.06,0:01.09,13264 +advent13,0.01,0:00.01,12300 +advent14,0.01,0:00.85,15068 +advent15,20.65,2:17.27,18101260 +advent16,15.74,2:24.64,45628 +advent17,3.94,0:20.67,22000 +advent18,0.02,0:00.06,14060 +advent19,87.22,18:54.12,14295324 +advent20,2.81,0:15.04,13940 +advent21,0.02,0:00.40,12680 +advent22,0.02,0:00.23,15908 +advent23,1.87,6:10.18,13628 +advent24,0.24,0:02.74,74820 +advent25,0.00,0:00.01,5896 -- 2.34.1 From ef8354646420ae6364603d2fea33955cf87c3a53 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Thu, 29 Dec 2022 16:09:33 +0000 Subject: [PATCH 10/16] Optimising day 15 --- README.md | 3 + advent-of-code22.cabal | 34 +++++++++- advent15/Main.hs | 54 ++++++++++++---- advent15/MainDirectParallel.hs | 115 +++++++++++++++++++++++++++++++++ advent15/MainLazy.hs | 99 ++++++++++++++++++++++++++++ advent15/MainOriginal.hs | 91 ++++++++++++++++++++++++++ advent15/MainSorted.hs | 102 +++++++++++++++++++++++++++++ advent15/advent15.png | Bin 0 -> 67626 bytes advent15/advent15directpar.png | Bin 0 -> 46558 bytes advent15/advent15lazy.png | Bin 0 -> 25751 bytes advent15/advent15times.csv | 9 +++ advent15/advent15times.md | 7 ++ 12 files changed, 499 insertions(+), 15 deletions(-) create mode 100644 advent15/MainDirectParallel.hs create mode 100644 advent15/MainLazy.hs create mode 100644 advent15/MainOriginal.hs create mode 100644 advent15/MainSorted.hs create mode 100644 advent15/advent15.png create mode 100644 advent15/advent15directpar.png create mode 100644 advent15/advent15lazy.png create mode 100644 advent15/advent15times.csv create mode 100644 advent15/advent15times.md diff --git a/README.md b/README.md index 7dcb1e7..a617b7c 100644 --- a/README.md +++ b/README.md @@ -86,9 +86,12 @@ executable advent01prof ghc-options: -O2 -Wall -threaded + -eventlog -rtsopts "-with-rtsopts=-N -p -s -hT" ``` +Only include the `-eventlog` directive if you want to use Threadscope to investigate parallel behaviour. + then running ``` diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 76f7671..54649c9 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -62,7 +62,7 @@ common common-extensions , RecordWildCards , ScopedTypeVariables , TemplateHaskell - , TransformListComp + -- , TransformListComp , TupleSections , TypeApplications , TypeFamilies @@ -171,10 +171,40 @@ executable advent14 main-is: advent14/Main.hs build-depends: text, attoparsec, containers, linear, lens +executable advent15original + import: common-extensions, build-directives + main-is: advent15/MainOriginal.hs + build-depends: text, attoparsec, containers, linear, lens + +executable advent15sorted + import: common-extensions, build-directives + main-is: advent15/MainSorted.hs + build-depends: text, attoparsec, containers, linear, lens + +executable advent15lazy + import: common-extensions, build-directives + main-is: advent15/MainLazy.hs + build-depends: text, attoparsec, containers, linear, lens + +executable advent15directpar + import: common-extensions, build-directives + main-is: advent15/MainDirectParallel.hs + build-depends: text, attoparsec, containers, linear, lens, parallel, deepseq + executable advent15 import: common-extensions, build-directives main-is: advent15/Main.hs - build-depends: text, attoparsec, containers, linear, lens + build-depends: text, attoparsec, containers, linear, lens, parallel, deepseq, split + +executable advent15prof + import: common-extensions, build-directives + main-is: advent15/Main.hs + build-depends: text, attoparsec, containers, linear, lens, parallel, deepseq, split + ghc-options: -O2 + -Wall + -threaded + -eventlog + -rtsopts "-with-rtsopts=-N -p -s -hT -ls" executable advent16 import: common-extensions, build-directives diff --git a/advent15/Main.hs b/advent15/Main.hs index 96f3213..097cf6b 100644 --- a/advent15/Main.hs +++ b/advent15/Main.hs @@ -5,14 +5,24 @@ import Data.Text (Text) import qualified Data.Text.IO as TIO import Data.Attoparsec.Text hiding (take, D) import Data.Ix -import qualified Data.Set as S +-- import qualified Data.Set as S import Linear hiding (Trace, trace, distance) +import Data.List (sortOn) +import Data.List.Split (chunksOf) +import Data.Ord (Down(..)) +-- import Data.Maybe +import Control.Parallel.Strategies -- (rpar, using, withStrategy, parList, parMap) +-- import Control.DeepSeq + type Position = V2 Int data Sensor = Sensor Position Position -- sensor position, beacon position deriving (Eq, Show) +instance Ord Sensor where + (Sensor s1 b1) `compare` (Sensor s2 b2) = (s1 `manhattan` b1) `compare` (s2 `manhattan` b2) + newtype Region = Region { getRegion :: Position -> Bool } instance Semigroup Region where @@ -27,9 +37,10 @@ main = do dataFileName <- getDataFileName text <- TIO.readFile dataFileName let sensors = successfulParse text + let coverage = mconcat $ fmap nearby $ sortOn Down sensors -- print sensors - print $ part1 sensors - print $ part2 sensors + print $ part1 sensors coverage + print $ part2 sensors coverage thisY :: Int -- thisY = 10 @@ -39,16 +50,33 @@ searchRange :: (Position, Position) -- searchRange = ((V2 0 0), (V2 20 20)) searchRange = ((V2 0 0), (V2 4000000 4000000)) -part1, part2 :: [Sensor] -> Int -part1 sensors = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords - where coverage = mconcat $ fmap nearby sensors - rowCoords = range ((V2 (globalMinX sensors) thisY), (V2 (globalMaxX sensors) thisY)) +part1, part2 :: [Sensor] -> Region -> Int +part1 sensors coverage = sum (fmap countForbidden rowChunks `using` (parList rseq)) + where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors + rowCoords = range ( (V2 (globalMinX sensors) thisY) + , (V2 (globalMaxX sensors) thisY) + ) + rowChunks = chunksOf 1000 rowCoords occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + -- forbidden = (filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords) `using` (parList rpar) + -- forbidden = (fmap (\p -> (getRegion coverage p, p)) rowCoords) `using` (parList rdeepseq) + countForbidden positions = + length $ filter (\p -> p `notElem` occupied) + $ filter (getRegion coverage) positions + +part2 sensors coverage = x * 4000000 + y + where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors + boundaries = fmap (filter (inRange searchRange)) + $ fmap justOutside sensors + -- holes = (fmap (filter (not . (getRegion coverage))) boundaries) `using` (parList rpar) + holes = fmap (filter (not . (getRegion coverage))) boundaries + `using` (parList rseq) + -- holes = (fmap (filter (not . (getRegion coverage))) boundaries) `using` (parList rpar) + -- holes = withStrategy (parList rpar) (fmap (filter (not . (getRegion coverage))) boundaries) + -- holes = using (fmap (filter (not . (getRegion coverage))) boundaries) (parList rpar) + -- holes = parMap rpar (filter (not . (getRegion coverage))) boundaries + V2 x y = head $ concat holes -part2 sensors = x * 4000000 + y - where coverage = mconcat $ fmap nearby sensors - boundaries = S.filter (inRange searchRange) $ S.unions $ fmap justOutside sensors - V2 x y = S.findMin $ S.filter (\p -> not $ getRegion coverage p) boundaries manhattan :: Position -> Position -> Int manhattan p1 p2 = (abs dx) + (abs dy) @@ -66,8 +94,8 @@ globalMinX, globalMaxX :: [Sensor] -> Int globalMinX = minimum . fmap minX globalMaxX = maximum . fmap maxX -justOutside :: Sensor -> S.Set Position -justOutside (Sensor s@(V2 sx sy) b) = S.fromList (topLeft ++ topRight ++ bottomLeft ++ bottomRight) +justOutside :: Sensor -> [Position] +justOutside (Sensor s@(V2 sx sy) b) = topLeft ++ topRight ++ bottomLeft ++ bottomRight where d = 1 + manhattan s b topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] diff --git a/advent15/MainDirectParallel.hs b/advent15/MainDirectParallel.hs new file mode 100644 index 0000000..ccf29d9 --- /dev/null +++ b/advent15/MainDirectParallel.hs @@ -0,0 +1,115 @@ +-- Writeup at https://work.njae.me.uk/2022/12/15/advent-of-code-2022-day-15/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Data.Ix +-- import qualified Data.Set as S +import Linear hiding (Trace, trace, distance) +import Data.List (sortOn) +import Data.Ord (Down(..)) +-- import Data.Maybe +import Control.Parallel.Strategies -- (rpar, using, withStrategy, parList, parMap) +-- import Control.DeepSeq + + +type Position = V2 Int + +data Sensor = Sensor Position Position -- sensor position, beacon position + deriving (Eq, Show) + +instance Ord Sensor where + (Sensor s1 b1) `compare` (Sensor s2 b2) = (s1 `manhattan` b1) `compare` (s2 `manhattan` b2) + +newtype Region = Region { getRegion :: Position -> Bool } + +instance Semigroup Region where + r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) + +instance Monoid Region where + -- mempty = Region (\p -> False) + mempty = Region (const False) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let sensors = successfulParse text + let coverage = mconcat $ fmap nearby $ sortOn Down sensors + -- print sensors + print $ part1 sensors coverage + print $ part2 sensors coverage + +thisY :: Int +-- thisY = 10 +thisY = 2000000 + +searchRange :: (Position, Position) +-- searchRange = ((V2 0 0), (V2 20 20)) +searchRange = ((V2 0 0), (V2 4000000 4000000)) + +part1, part2 :: [Sensor] -> Region -> Int +part1 sensors coverage = length $ filter (\p -> p `notElem` occupied) + $ fmap snd $ filter fst forbidden + where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors + rowCoords = range ( (V2 (globalMinX sensors) thisY) + , (V2 (globalMaxX sensors) thisY) + ) + occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + -- forbidden = (filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords) `using` (parList rpar) + forbidden = (fmap (\p -> (getRegion coverage p, p)) rowCoords) + `using` (parList rdeepseq) + +part2 sensors coverage = x * 4000000 + y + where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors + boundaries = fmap (filter (inRange searchRange)) + $ fmap justOutside sensors + holes = (fmap (filter (not . (getRegion coverage))) boundaries) + `using` (parList rpar) + -- holes = (fmap (filter (not . (getRegion coverage))) boundaries) `using` (parList rpar) + -- holes = withStrategy (parList rpar) (fmap (filter (not . (getRegion coverage))) boundaries) + -- holes = using (fmap (filter (not . (getRegion coverage))) boundaries) (parList rpar) + -- holes = parMap rpar (filter (not . (getRegion coverage))) boundaries + V2 x y = head $ concat holes + + +manhattan :: Position -> Position -> Int +manhattan p1 p2 = (abs dx) + (abs dy) + where V2 dx dy = p1 ^-^ p2 + +nearby :: Sensor -> Region +nearby (Sensor s b) = Region (\p -> manhattan s p <= dist) + where dist = manhattan s b + +minX, maxX :: Sensor -> Int +minX (Sensor s@(V2 sx _) b) = sx - (manhattan s b) +maxX (Sensor s@(V2 sx _) b) = sx + (manhattan s b) + +globalMinX, globalMaxX :: [Sensor] -> Int +globalMinX = minimum . fmap minX +globalMaxX = maximum . fmap maxX + +justOutside :: Sensor -> [Position] +justOutside (Sensor s@(V2 sx sy) b) = topLeft ++ topRight ++ bottomLeft ++ bottomRight + where d = 1 + manhattan s b + topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] + topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] + bottomLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy, (sy - 1)..(sy - d)] ] + bottomRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy, (sy - 1)..(sy - d)] ] + +-- Parse the input file + +sensorsP :: Parser [Sensor] +sensorP :: Parser Sensor +positionP :: Parser Position + +sensorsP = sensorP `sepBy` endOfLine +sensorP = Sensor <$> ("Sensor at " *> positionP) <*> (": closest beacon is at " *> positionP) +positionP = V2 <$> (("x=" *> signed decimal) <* ", ") <*> ("y=" *> signed decimal) + +successfulParse :: Text -> [Sensor] +successfulParse input = + case parseOnly sensorsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right sensors -> sensors diff --git a/advent15/MainLazy.hs b/advent15/MainLazy.hs new file mode 100644 index 0000000..8b85ccc --- /dev/null +++ b/advent15/MainLazy.hs @@ -0,0 +1,99 @@ +-- Writeup at https://work.njae.me.uk/2022/12/15/advent-of-code-2022-day-15/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Data.Ix +-- import qualified Data.Set as S +import Linear hiding (Trace, trace, distance) +import Data.List (sortOn) +import Data.Ord (Down(..)) +-- import Data.Maybe + + +type Position = V2 Int + +data Sensor = Sensor Position Position -- sensor position, beacon position + deriving (Eq, Show) + +instance Ord Sensor where + (Sensor s1 b1) `compare` (Sensor s2 b2) = (s1 `manhattan` b1) `compare` (s2 `manhattan` b2) + +newtype Region = Region { getRegion :: Position -> Bool } + +instance Semigroup Region where + r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) + +instance Monoid Region where + -- mempty = Region (\p -> False) + mempty = Region (const False) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let sensors = successfulParse text + -- print sensors + print $ part1 sensors + print $ part2 sensors + +thisY :: Int +-- thisY = 10 +thisY = 2000000 + +searchRange :: (Position, Position) +-- searchRange = ((V2 0 0), (V2 20 20)) +searchRange = ((V2 0 0), (V2 4000000 4000000)) + +part1, part2 :: [Sensor] -> Int +part1 sensors = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords + where coverage = mconcat $ fmap nearby $ sortOn Down sensors + rowCoords = range ((V2 (globalMinX sensors) thisY), (V2 (globalMaxX sensors) thisY)) + occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + +part2 sensors = x * 4000000 + y + where coverage = mconcat $ fmap nearby $ sortOn Down sensors + boundaries = fmap (filter (inRange searchRange)) $ fmap justOutside sensors + V2 x y = head $ concat $ fmap (filter (not . (getRegion coverage))) boundaries + + +manhattan :: Position -> Position -> Int +manhattan p1 p2 = (abs dx) + (abs dy) + where V2 dx dy = p1 ^-^ p2 + +nearby :: Sensor -> Region +nearby (Sensor s b) = Region (\p -> manhattan s p <= dist) + where dist = manhattan s b + +minX, maxX :: Sensor -> Int +minX (Sensor s@(V2 sx _) b) = sx - (manhattan s b) +maxX (Sensor s@(V2 sx _) b) = sx + (manhattan s b) + +globalMinX, globalMaxX :: [Sensor] -> Int +globalMinX = minimum . fmap minX +globalMaxX = maximum . fmap maxX + +justOutside :: Sensor -> [Position] +justOutside (Sensor s@(V2 sx sy) b) = topLeft ++ topRight ++ bottomLeft ++ bottomRight + where d = 1 + manhattan s b + topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] + topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] + bottomLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy, (sy - 1)..(sy - d)] ] + bottomRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy, (sy - 1)..(sy - d)] ] + +-- Parse the input file + +sensorsP :: Parser [Sensor] +sensorP :: Parser Sensor +positionP :: Parser Position + +sensorsP = sensorP `sepBy` endOfLine +sensorP = Sensor <$> ("Sensor at " *> positionP) <*> (": closest beacon is at " *> positionP) +positionP = V2 <$> (("x=" *> signed decimal) <* ", ") <*> ("y=" *> signed decimal) + +successfulParse :: Text -> [Sensor] +successfulParse input = + case parseOnly sensorsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right sensors -> sensors diff --git a/advent15/MainOriginal.hs b/advent15/MainOriginal.hs new file mode 100644 index 0000000..d04b1ea --- /dev/null +++ b/advent15/MainOriginal.hs @@ -0,0 +1,91 @@ +-- Writeup at https://work.njae.me.uk/2022/12/15/advent-of-code-2022-day-15/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Data.Ix +import qualified Data.Set as S +import Linear hiding (Trace, trace, distance) + +type Position = V2 Int + +data Sensor = Sensor Position Position -- sensor position, beacon position + deriving (Eq, Show) + +newtype Region = Region { getRegion :: Position -> Bool } + +instance Semigroup Region where + r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) + +instance Monoid Region where + -- mempty = Region (\p -> False) + mempty = Region (const False) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let sensors = successfulParse text + -- print sensors + print $ part1 sensors + print $ part2 sensors + +thisY :: Int +-- thisY = 10 +thisY = 2000000 + +searchRange :: (Position, Position) +-- searchRange = ((V2 0 0), (V2 20 20)) +searchRange = ((V2 0 0), (V2 4000000 4000000)) + +part1, part2 :: [Sensor] -> Int +part1 sensors = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords + where coverage = mconcat $ fmap nearby sensors + rowCoords = range ((V2 (globalMinX sensors) thisY), (V2 (globalMaxX sensors) thisY)) + occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + +part2 sensors = x * 4000000 + y + where coverage = mconcat $ fmap nearby sensors + boundaries = {-# SCC boundaries #-} S.filter (inRange searchRange) $ S.unions $ fmap justOutside sensors + V2 x y = {-# SCC findMinV #-} S.findMin $ S.filter (not . (getRegion coverage)) boundaries + +manhattan :: Position -> Position -> Int +manhattan p1 p2 = (abs dx) + (abs dy) + where V2 dx dy = p1 ^-^ p2 + +nearby :: Sensor -> Region +nearby (Sensor s b) = Region (\p -> manhattan s p <= dist) + where dist = manhattan s b + +minX, maxX :: Sensor -> Int +minX (Sensor s@(V2 sx _) b) = sx - (manhattan s b) +maxX (Sensor s@(V2 sx _) b) = sx + (manhattan s b) + +globalMinX, globalMaxX :: [Sensor] -> Int +globalMinX = minimum . fmap minX +globalMaxX = maximum . fmap maxX + +justOutside :: Sensor -> S.Set Position +justOutside (Sensor s@(V2 sx sy) b) = S.fromList (topLeft ++ topRight ++ bottomLeft ++ bottomRight) + where d = 1 + manhattan s b + topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] + topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] + bottomLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy, (sy - 1)..(sy - d)] ] + bottomRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy, (sy - 1)..(sy - d)] ] + +-- Parse the input file + +sensorsP :: Parser [Sensor] +sensorP :: Parser Sensor +positionP :: Parser Position + +sensorsP = sensorP `sepBy` endOfLine +sensorP = Sensor <$> ("Sensor at " *> positionP) <*> (": closest beacon is at " *> positionP) +positionP = V2 <$> (("x=" *> signed decimal) <* ", ") <*> ("y=" *> signed decimal) + +successfulParse :: Text -> [Sensor] +successfulParse input = + case parseOnly sensorsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right sensors -> sensors diff --git a/advent15/MainSorted.hs b/advent15/MainSorted.hs new file mode 100644 index 0000000..7fcd5e0 --- /dev/null +++ b/advent15/MainSorted.hs @@ -0,0 +1,102 @@ +-- Writeup at https://work.njae.me.uk/2022/12/15/advent-of-code-2022-day-15/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Data.Ix +import qualified Data.Set as S +import Linear hiding (Trace, trace, distance) +import Data.List (sortOn) +import Data.Ord (Down(..)) + + +type Position = V2 Int + +data Sensor = Sensor Position Position -- sensor position, beacon position + deriving (Eq, Show) + +instance Ord Sensor where + -- (Sensor s1 b1) `compare` (Sensor s2 b2) + -- | cmp == EQ = s1 `compare` s2 + -- | otherwise = cmp + -- where cmp = (s1 `manhattan` b1) `compare` (s2 `manhattan` b2) + (Sensor s1 b1) `compare` (Sensor s2 b2) + = (s1 `manhattan` b1) `compare` (s2 `manhattan` b2) + +newtype Region = Region { getRegion :: Position -> Bool } + +instance Semigroup Region where + r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) + +instance Monoid Region where + -- mempty = Region (\p -> False) + mempty = Region (const False) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let sensors = successfulParse text + -- print sensors + print $ part1 sensors + print $ part2 sensors + +thisY :: Int +-- thisY = 10 +thisY = 2000000 + +searchRange :: (Position, Position) +-- searchRange = ((V2 0 0), (V2 20 20)) +searchRange = ((V2 0 0), (V2 4000000 4000000)) + +part1, part2 :: [Sensor] -> Int +part1 sensors = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords + where coverage = mconcat $ fmap nearby $ sortOn Down sensors + rowCoords = range ((V2 (globalMinX sensors) thisY), (V2 (globalMaxX sensors) thisY)) + occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + +part2 sensors = x * 4000000 + y + where coverage = mconcat $ fmap nearby $ sortOn Down sensors + boundaries = {-# SCC boundaries #-} S.filter (inRange searchRange) $ S.unions $ fmap justOutside sensors + V2 x y = {-# SCC findMinV #-} S.findMin $ S.filter (not . (getRegion coverage)) boundaries + +manhattan :: Position -> Position -> Int +manhattan p1 p2 = (abs dx) + (abs dy) + where V2 dx dy = p1 ^-^ p2 + +nearby :: Sensor -> Region +nearby (Sensor s b) = Region (\p -> manhattan s p <= dist) + where dist = manhattan s b + +minX, maxX :: Sensor -> Int +minX (Sensor s@(V2 sx _) b) = sx - (manhattan s b) +maxX (Sensor s@(V2 sx _) b) = sx + (manhattan s b) + +globalMinX, globalMaxX :: [Sensor] -> Int +globalMinX = minimum . fmap minX +globalMaxX = maximum . fmap maxX + +justOutside :: Sensor -> S.Set Position +justOutside (Sensor s@(V2 sx sy) b) = S.fromList (topLeft ++ topRight ++ bottomLeft ++ bottomRight) + where d = 1 + manhattan s b + topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] + topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] + bottomLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy, (sy - 1)..(sy - d)] ] + bottomRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy, (sy - 1)..(sy - d)] ] + +-- Parse the input file + +sensorsP :: Parser [Sensor] +sensorP :: Parser Sensor +positionP :: Parser Position + +sensorsP = sensorP `sepBy` endOfLine +sensorP = Sensor <$> ("Sensor at " *> positionP) <*> (": closest beacon is at " *> positionP) +positionP = V2 <$> (("x=" *> signed decimal) <* ", ") <*> ("y=" *> signed decimal) + +successfulParse :: Text -> [Sensor] +successfulParse input = + case parseOnly sensorsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right sensors -> sensors diff --git a/advent15/advent15.png b/advent15/advent15.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfeee906ec02012ad722cffc2baed07ac278c95 GIT binary patch literal 67626 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 literal 0 HcmV?d00001 diff --git a/advent15/advent15directpar.png b/advent15/advent15directpar.png new file mode 100644 index 0000000000000000000000000000000000000000..3ed68ac5f5fec5bcc435ed80dea9063d511a8916 GIT binary patch literal 46558 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[qB2mAlF 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 Date: Thu, 29 Dec 2022 16:19:16 +0000 Subject: [PATCH 11/16] Tidying --- advent15/Main.hs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/advent15/Main.hs b/advent15/Main.hs index 097cf6b..664e47d 100644 --- a/advent15/Main.hs +++ b/advent15/Main.hs @@ -52,29 +52,20 @@ searchRange = ((V2 0 0), (V2 4000000 4000000)) part1, part2 :: [Sensor] -> Region -> Int part1 sensors coverage = sum (fmap countForbidden rowChunks `using` (parList rseq)) - where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors - rowCoords = range ( (V2 (globalMinX sensors) thisY) + where rowCoords = range ( (V2 (globalMinX sensors) thisY) , (V2 (globalMaxX sensors) thisY) ) rowChunks = chunksOf 1000 rowCoords occupied = concatMap (\(Sensor s b) -> [s, b]) sensors - -- forbidden = (filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords) `using` (parList rpar) - -- forbidden = (fmap (\p -> (getRegion coverage p, p)) rowCoords) `using` (parList rdeepseq) countForbidden positions = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) positions part2 sensors coverage = x * 4000000 + y - where -- coverage = mconcat $ fmap nearby $ sortOn Down sensors - boundaries = fmap (filter (inRange searchRange)) + where boundaries = fmap (filter (inRange searchRange)) $ fmap justOutside sensors - -- holes = (fmap (filter (not . (getRegion coverage))) boundaries) `using` (parList rpar) holes = fmap (filter (not . (getRegion coverage))) boundaries `using` (parList rseq) - -- holes = (fmap (filter (not . (getRegion coverage))) boundaries) `using` (parList rpar) - -- holes = withStrategy (parList rpar) (fmap (filter (not . (getRegion coverage))) boundaries) - -- holes = using (fmap (filter (not . (getRegion coverage))) boundaries) (parList rpar) - -- holes = parMap rpar (filter (not . (getRegion coverage))) boundaries V2 x y = head $ concat holes -- 2.34.1 From c96b3e327eb7f937787e9ac846d8f7c354bfa4a1 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 2 Jan 2023 16:51:59 +0000 Subject: [PATCH 12/16] Day 23 now using arrays --- advent-of-code22.cabal | 9 +- advent23/Main.hs | 282 +++++++++++++++++++++------------------ advent23/MainOriginal.hs | 217 ++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+), 129 deletions(-) create mode 100644 advent23/MainOriginal.hs diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 54649c9..24f58ef 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -241,15 +241,20 @@ executable advent22 main-is: advent22/Main.hs build-depends: containers, linear, lens, mtl +executable advent23original + import: common-extensions, build-directives + main-is: advent23/MainOriginal.hs + build-depends: containers, linear, lens, mtl, multiset + executable advent23 import: common-extensions, build-directives main-is: advent23/Main.hs - build-depends: containers, linear, lens, mtl, multiset + build-depends: linear, lens, mtl, array executable advent23prof import: common-extensions, build-directives main-is: advent23/Main.hs - build-depends: containers, linear, lens, mtl, multiset + build-depends: linear, lens, mtl, array ghc-options: -O2 -Wall -threaded diff --git a/advent23/Main.hs b/advent23/Main.hs index 194a8ea..08eef6c 100644 --- a/advent23/Main.hs +++ b/advent23/Main.hs @@ -1,57 +1,48 @@ --- Writeup at https://work.njae.me.uk/2022/12/23/advent-of-code-2022-day-23/ +-- Writeup at https://work.njae.me.uk/2023/01/02/optimising-haskell-example-2/ -- import Debug.Trace import AoC -import qualified Data.Set as S import Linear -import Control.Lens import Data.Ix -import Data.Maybe --- import Data.Char import Data.Monoid -import Data.MultiSet as MS import Control.Monad.State.Strict +import Control.Monad.ST +import qualified Data.Array.IArray as A +import qualified Data.Array.MArray as M +import Data.Array.ST +import Data.Maybe -type Position = V2 Int -- r, c +type Position = V2 Int -- x, y data Direction = North | South | West | East deriving (Show, Eq, Ord, Enum, Bounded) -data Elf = Elf { _current :: Position, _proposed :: Position} - -- deriving (Show, Eq, Ord) - -- deriving (Eq, Ord) -makeLenses ''Elf - -instance Show Elf where - show elf = "Elf {c= " ++ (show (elf ^. current)) - ++ ", p= " ++ (show (elf ^. proposed)) - ++ " -> " ++ (show (directionOfElf elf)) - ++ "}" +newtype Elf = Elf Position + deriving (Eq, Ord, Show) -instance Eq Elf where - e1 == e2 = (_current e1) == (_current e2) +type Population = A.Array Position (Maybe Elf) -instance Ord Elf where - e1 `compare` e2 = (_current e1) `compare` (_current e2) +type MPopulation s = STArray s Position (Maybe Elf) +type MClashCounts s = STArray s Position Int -data Grove = Grove { currentGrove :: S.Set Elf, proposalDirections :: [Direction], elapsedRounds :: Int} +data Grove = Grove { currentGrove :: Population, proposalDirections :: [Direction], elapsedRounds :: Int} deriving (Eq) instance Show Grove where - show grove = (show $ currentGrove grove) ++ ", " ++ (show $ take 4 $ proposalDirections grove) ++ ", e = " ++ (show $ elapsedRounds grove) + show grove = (showElves $ currentGrove grove) ++ ", " ++ (show $ take 4 $ proposalDirections grove) ++ ", e = " ++ (show $ elapsedRounds grove) + where showElves g = "Grove " ++ (show $ A.bounds g) ++ " " ++ (show $ filter (isJust . snd) $ A.assocs g) type GroveState = State Grove - main :: IO () main = do dataFileName <- getDataFileName text <- readFile dataFileName let grove = Grove (mkGrove text) (cycle [North .. East]) 0 -- print grove - -- print $ execState simulateOnce grove + -- print $ runState simulateOnce grove -- print $ execState (simulateN 4) grove print $ part1 grove print $ part2 grove @@ -64,16 +55,9 @@ part1 grove = countEmpty grove' bounds part2 grove = elapsedRounds grove' where grove' = execState simulateToCompletion grove -directionOfElf :: Elf -> Maybe Direction -directionOfElf elf - | delta == V2 0 1 = Just North - | delta == V2 0 -1 = Just South - | delta == V2 1 0 = Just East - | delta == V2 -1 0 = Just West - | otherwise = Nothing - where delta = (elf ^. proposed) ^-^ (elf ^. current) -simulateToCompletion, simulateOnce, proposeMoves, removeClashes, moveElves, updateDirections, updateCount :: GroveState () +simulateToCompletion, simulateOnce, growGrove, updateDirections, updateCount :: GroveState () + simulateToCompletion = do oldGrove <- gets currentGrove simulateOnce @@ -89,27 +73,27 @@ simulateN n = simulateN (n - 1) simulateOnce = - do proposeMoves - removeClashes - moveElves - updateDirections - updateCount - -proposeMoves = - do grove <- gets currentGrove - proposalsInf <- gets proposalDirections - let proposals = take 4 proposalsInf - let grove' = S.map (makeProposal grove proposals) grove - modify' (\g -> g { currentGrove = grove'}) - -removeClashes = - do grove <- gets currentGrove - let clashes = findClashes grove - stopClashingElves clashes - -moveElves = + do grove <- gets currentGrove + proposalsInf <- gets proposalDirections + let proposals = take 4 proposalsInf + let newGrove = + runSTArray $ + do mPopulation <- M.thaw grove + mCounts <- M.mapArray (const 0) mPopulation + proposeMoves mPopulation mCounts proposals + removeClashes mPopulation mCounts + moveElves mPopulation + return mPopulation + modify' (\g -> g { currentGrove = newGrove}) + growGrove + updateDirections + updateCount + +growGrove = do grove <- gets currentGrove - let grove' = S.map moveElf grove + let (b0, b1) = findBounds grove + let bounds' = (b0 ^+^ (V2 -1 -1), b1 ^+^ (V2 1 1)) + let grove' = A.accumArray (flip const) Nothing bounds' $ filter ((inRange bounds') . fst ) $ A.assocs grove modify' (\g -> g { currentGrove = grove'}) updateDirections = modify' (\g -> g { proposalDirections = tail (proposalDirections g)}) @@ -117,99 +101,143 @@ updateCount = modify' (\g -> g { elapsedRounds = (elapsedRounds g) + 1}) -- position changing utilities -anyNeighbour :: S.Set Position -anyNeighbour = S.fromList [ V2 dx dy - | dx <- [-1, 0, 1] - , dy <- [-1, 0, 1] - , not ((dx == 0) && (dy == 0)) - ] +anyNeighbour :: [Position] +anyNeighbour = [ V2 dx dy + | dx <- [-1, 0, 1] + , dy <- [-1, 0, 1] + , not ((dx == 0) && (dy == 0)) + ] -directionNeighbour :: Direction -> S.Set Position -directionNeighbour North = S.filter (\d -> d ^. _y == 1) anyNeighbour -directionNeighbour South = S.filter (\d -> d ^. _y == -1) anyNeighbour -directionNeighbour West = S.filter (\d -> d ^. _x == -1) anyNeighbour -directionNeighbour East = S.filter (\d -> d ^. _x == 1) anyNeighbour +directionNeighbour :: Direction -> [Position] +directionNeighbour North = filter (\(V2 _x y) -> y == 1) anyNeighbour +directionNeighbour South = filter (\(V2 _x y) -> y == -1) anyNeighbour +directionNeighbour West = filter (\(V2 x _y) -> x == -1) anyNeighbour +directionNeighbour East = filter (\(V2 x _y) -> x == 1) anyNeighbour -stepDelta ::Direction -> Position +stepDelta :: Direction -> Position stepDelta North = V2 0 1 stepDelta South = V2 0 -1 stepDelta West = V2 -1 0 stepDelta East = V2 1 0 -translateTo :: Position -> S.Set Position -> S.Set Position -translateTo here deltas = S.map (here ^+^) deltas +noElves :: MPopulation s -> [Position] -> ST s Bool +noElves elves tests = + do others <- mapM (M.readArray elves) tests + return $ all isNothing others -noElves :: S.Set Elf -> S.Set Position -> Bool -noElves elves tests = S.null $ S.intersection tests $ S.map _current elves +isolated :: MPopulation s -> Position -> ST s Bool +isolated elves here = noElves elves $ fmap (here ^+^) anyNeighbour -- get elves to make proposals -isolated :: S.Set Elf -> Elf -> Bool -isolated elves elf = noElves elves $ translateTo (elf ^. current) $ anyNeighbour - -nearby :: S.Set Elf -> Elf -> S.Set Elf -nearby elves elf = S.filter (\e -> (e ^. current) `S.member` nbrs) elves - where nbrs = translateTo (elf ^. current) $ anyNeighbour - -makeProposal :: S.Set Elf -> [Direction] -> Elf -> Elf -makeProposal grove directions elf - | isolated localElves elf = elf - | otherwise = fromMaybe elf $ getFirst $ mconcat $ fmap First $ fmap (proposedStep localElves elf) directions - where localElves = nearby grove elf - -proposedStep :: S.Set Elf -> Elf -> Direction -> Maybe Elf -proposedStep grove elf direction - | noElves grove interfering = Just $ elf & proposed .~ (here ^+^ (stepDelta direction)) - | otherwise = Nothing - where here = elf ^. current - interfering = translateTo here $ directionNeighbour direction +proposeMoves :: MPopulation s -> MClashCounts s -> [Direction] -> ST s () +proposeMoves mPopulation mCounts proposals = + do assocs <- M.getAssocs mPopulation + mapM_ (makeProposal mPopulation mCounts proposals) assocs + +makeProposal :: MPopulation s -> MClashCounts s -> [Direction] -> (Position, Maybe Elf) -> ST s () +makeProposal elves clashes directions (here, elf) + | isNothing elf = return () + | otherwise = do isIsolated <- isolated elves here + unless isIsolated + do proposals <- mapM (proposedStep elves here) directions + let step = fromMaybe (V2 0 0) $ getFirst $ mconcat $ fmap First proposals + let there = here ^+^ step + thereCount <- M.readArray clashes there + M.writeArray clashes there (thereCount + 1) + M.writeArray elves here (Just (Elf there)) + +proposedStep :: MPopulation s -> Position -> Direction -> ST s (Maybe Position) +proposedStep elves here direction = + do isFree <- noElves elves interfering + if isFree + then return $ Just $ stepDelta direction + else return Nothing + where interfering = fmap (here ^+^) $ directionNeighbour direction -- find clashing elves and prevent them moving -findClashes :: S.Set Elf -> S.Set Position -findClashes grove = MS.toSet $ MS.foldOccur ifMany MS.empty targets - where targets = MS.map _proposed $ MS.fromSet grove - ifMany t n s - | n == 1 = s - | otherwise = MS.insert t s - -stopClashingElves :: S.Set Position -> GroveState () -stopClashingElves clashes = - do grove <- gets currentGrove - let grove' = S.map (notClash clashes) grove - modify' (\g -> g { currentGrove = grove'}) +removeClashes :: MPopulation s -> MClashCounts s -> ST s () +removeClashes elves counts = + do cts <- M.getAssocs counts + let clashes = fmap fst $ filter ((> 1) . snd) cts + stopClashingElves clashes elves -notClash :: S.Set Position -> Elf -> Elf -notClash clashes elf - | (elf ^. proposed) `S.member` clashes = elf & proposed .~ (elf ^. current) - | otherwise = elf +stopClashingElves :: [Position] -> MPopulation s -> ST s () +stopClashingElves clashes elves = mapM_ stopClash targets + where targets = concatMap findNbrs clashes + findNbrs c = fmap (^+^ c) $ fmap stepDelta [North .. East] + stopClash here = + do target <- M.readArray elves here + when (isJust target) $ M.writeArray elves here (Just (Elf here)) -- the elves move -moveElf :: Elf -> Elf -moveElf elf = elf & current .~ (elf ^. proposed) - --- part 1 solution utilities - -findBounds :: S.Set Elf -> (Position, Position) -findBounds grove = ((V2 minX minY), (V2 maxX maxY)) - where minX = fromJust $ minimumOf (folded . current . _x) grove - minY = fromJust $ minimumOf (folded . current . _y) grove - maxX = fromJust $ maximumOf (folded . current . _x) grove - maxY = fromJust $ maximumOf (folded . current . _y) grove - -countEmpty :: S.Set Elf -> (Position, Position) -> Int -countEmpty grove bounds = (rangeSize bounds) - (S.size grove) +moveElves :: MPopulation s -> ST s () +moveElves elves = + do assocs <- M.getAssocs elves + mapM_ (moveElf elves) assocs + +moveElf :: MPopulation s -> (Position, Maybe Elf) -> ST s () +moveElf _elves (_here, Nothing) = return () +moveElf elves (here, Just (Elf there)) = + do M.writeArray elves here Nothing + M.writeArray elves there (Just (Elf there)) + +-- reset the array bounds + +findBounds :: Population -> (Position, Position) +findBounds grove = boundsR + where bounds0 = A.bounds grove + boundsT = shrink grove topStrip topShrink bounds0 + boundsB = shrink grove bottomStrip bottomShrink boundsT + boundsL = shrink grove leftStrip leftShrink boundsB + boundsR = shrink grove rightStrip rightShrink boundsL + +shrink :: Population + -> ((Position, Position) -> (Position, Position)) + -> (Position, Position) + -> (Position, Position) + -> (Position, Position) +shrink grove findStrip stripDirection currentBounds + | emptyStrip grove (findStrip currentBounds) = + shrink grove findStrip stripDirection (shiftBounds currentBounds stripDirection) + | otherwise = currentBounds + where shiftBounds (b0, b1) (d0, d1) = (b0 ^+^ d0, b1 ^+^ d1) + +emptyStrip :: Population -> (Position, Position) -> Bool +emptyStrip grove strip = all isNothing $ fmap (grove A.!) $ range strip + +topStrip, bottomStrip, leftStrip, rightStrip :: (Position, Position) -> (Position, Position) +topStrip (V2 minX _minY, V2 maxX maxY) = (V2 minX maxY, V2 maxX maxY) +bottomStrip (V2 minX minY, V2 maxX _maxY) = (V2 minX minY, V2 maxX minY) +leftStrip (V2 minX minY, V2 _maxX maxY) = (V2 minX minY, V2 minX maxY) +rightStrip (V2 _minX minY, V2 maxX maxY) = (V2 maxX minY, V2 maxX maxY) + +topShrink, bottomShrink, leftShrink, rightShrink :: (Position, Position) +topShrink = (V2 0 0, V2 0 -1) +bottomShrink = (V2 0 1, V2 0 0) +leftShrink = (V2 1 0, V2 0 0) +rightShrink = (V2 0 0, V2 -1 0) + +countEmpty :: Population -> (Position, Position) -> Int +countEmpty grove bounds = length $ filter isNothing $ fmap (grove A.!) cells + where cells = range bounds -- Parse the input file -mkGrove :: String -> S.Set Elf -mkGrove text = S.fromList - [ Elf (V2 x y) (V2 x y) - | x <- [0..maxX], y <- [0..maxY] - , isElf x y +mkGrove :: String -> Population +mkGrove text = A.accumArray + (\_ e -> e) + Nothing + (V2 -1 -1, V2 maxX maxY) + [ mkElf x y -- Elf (V2 x y) (V2 x y) + | x <- [0..(maxX - 1)], y <- [0..(maxY - 1)] + -- , isElf x y ] where rows = reverse $ lines text - maxY = length rows - 1 - maxX = (length $ head rows) - 1 - isElf x y = ((rows !! y) !! x) == '#' + maxY = length rows + maxX = (length $ head rows) + mkElf x y + | ((rows !! y) !! x) == '#' = ((V2 x y), Just ( Elf (V2 x y) )) + | otherwise = ((V2 x y), Nothing) diff --git a/advent23/MainOriginal.hs b/advent23/MainOriginal.hs new file mode 100644 index 0000000..6296489 --- /dev/null +++ b/advent23/MainOriginal.hs @@ -0,0 +1,217 @@ +-- Writeup at https://work.njae.me.uk/2022/12/23/advent-of-code-2022-day-23/ + +-- import Debug.Trace + +import AoC +import qualified Data.Set as S +import Linear +import Control.Lens +import Data.Ix +import Data.Maybe +-- import Data.Char +import Data.Monoid +import Data.MultiSet as MS +import Control.Monad.State.Strict + + +type Position = V2 Int -- r, c + +data Direction = North | South | West | East + deriving (Show, Eq, Ord, Enum, Bounded) + +data Elf = Elf { _current :: Position, _proposed :: Position} + -- deriving (Show, Eq, Ord) + -- deriving (Eq, Ord) +makeLenses ''Elf + +instance Show Elf where + show elf = "Elf {c= " ++ (show (elf ^. current)) + ++ ", p= " ++ (show (elf ^. proposed)) + ++ " -> " ++ (show (directionOfElf elf)) + ++ "}" + +instance Eq Elf where + e1 == e2 = (_current e1) == (_current e2) + +instance Ord Elf where + e1 `compare` e2 = (_current e1) `compare` (_current e2) + +type Population = S.Set Elf + +data Grove = Grove { currentGrove :: Population, proposalDirections :: [Direction], elapsedRounds :: Int} + deriving (Eq) + +instance Show Grove where + show grove = (show $ currentGrove grove) ++ ", " ++ (show $ take 4 $ proposalDirections grove) ++ ", e = " ++ (show $ elapsedRounds grove) + +type GroveState = State Grove + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- readFile dataFileName + let grove = Grove (mkGrove text) (cycle [North .. East]) 0 + -- print grove + -- print $ execState simulateOnce grove + -- print $ execState (simulateN 4) grove + print $ part1 grove + print $ part2 grove + +part1, part2 :: Grove -> Int +part1 grove = countEmpty grove' bounds + where grove' = currentGrove $ execState (simulateN 10) grove + bounds = findBounds grove' + +part2 grove = elapsedRounds grove' + where grove' = execState simulateToCompletion grove + +directionOfElf :: Elf -> Maybe Direction +directionOfElf elf + | delta == V2 0 1 = Just North + | delta == V2 0 -1 = Just South + | delta == V2 1 0 = Just East + | delta == V2 -1 0 = Just West + | otherwise = Nothing + where delta = (elf ^. proposed) ^-^ (elf ^. current) + +simulateToCompletion, simulateOnce, proposeMoves, removeClashes, moveElves, updateDirections, updateCount :: GroveState () +simulateToCompletion = + do oldGrove <- gets currentGrove + simulateOnce + newGrove <- gets currentGrove + if oldGrove == newGrove + then return () + else simulateToCompletion + +simulateN :: Int -> GroveState () +simulateN 0 = return () +simulateN n = + do simulateOnce + simulateN (n - 1) + +simulateOnce = + do proposeMoves + removeClashes + moveElves + updateDirections + updateCount + +proposeMoves = + do grove <- gets currentGrove + proposalsInf <- gets proposalDirections + let proposals = take 4 proposalsInf + let grove' = S.map (makeProposal grove proposals) grove + modify' (\g -> g { currentGrove = grove'}) + +removeClashes = + do grove <- gets currentGrove + let clashes = findClashes grove + stopClashingElves clashes + +moveElves = + do grove <- gets currentGrove + let grove' = S.map moveElf grove + modify' (\g -> g { currentGrove = grove'}) + +updateDirections = modify' (\g -> g { proposalDirections = tail (proposalDirections g)}) +updateCount = modify' (\g -> g { elapsedRounds = (elapsedRounds g) + 1}) + +-- position changing utilities + +anyNeighbour :: S.Set Position +anyNeighbour = S.fromList [ V2 dx dy + | dx <- [-1, 0, 1] + , dy <- [-1, 0, 1] + , not ((dx == 0) && (dy == 0)) + ] + +directionNeighbour :: Direction -> S.Set Position +directionNeighbour North = S.filter (\d -> d ^. _y == 1) anyNeighbour +directionNeighbour South = S.filter (\d -> d ^. _y == -1) anyNeighbour +directionNeighbour West = S.filter (\d -> d ^. _x == -1) anyNeighbour +directionNeighbour East = S.filter (\d -> d ^. _x == 1) anyNeighbour + +stepDelta :: Direction -> Position +stepDelta North = V2 0 1 +stepDelta South = V2 0 -1 +stepDelta West = V2 -1 0 +stepDelta East = V2 1 0 + +translateTo :: Position -> S.Set Position -> S.Set Position +translateTo here deltas = S.map (here ^+^) deltas + +noElves :: Population -> S.Set Position -> Bool +noElves elves tests = S.null $ S.intersection tests $ S.map _current elves + +-- get elves to make proposals + +isolated :: Population -> Elf -> Bool +isolated elves elf = noElves elves $ translateTo (elf ^. current) $ anyNeighbour + +nearby :: Population -> Elf -> Population +nearby elves elf = S.filter (\e -> (e ^. current) `S.member` nbrs) elves + where nbrs = translateTo (elf ^. current) $ anyNeighbour + +makeProposal :: Population -> [Direction] -> Elf -> Elf +makeProposal grove directions elf + | isolated localElves elf = elf + | otherwise = fromMaybe elf $ getFirst $ mconcat $ fmap First $ fmap (proposedStep localElves elf) directions + where localElves = nearby grove elf + +proposedStep :: Population -> Elf -> Direction -> Maybe Elf +proposedStep grove elf direction + | noElves grove interfering = Just $ elf & proposed .~ (here ^+^ (stepDelta direction)) + | otherwise = Nothing + where here = elf ^. current + interfering = translateTo here $ directionNeighbour direction + +-- find clashing elves and prevent them moving + +findClashes :: Population -> S.Set Position +findClashes grove = MS.toSet $ MS.foldOccur ifMany MS.empty targets + where targets = MS.map _proposed $ MS.fromSet grove + ifMany t n s + | n == 1 = s + | otherwise = MS.insert t s + +stopClashingElves :: S.Set Position -> GroveState () +stopClashingElves clashes = + do grove <- gets currentGrove + let grove' = S.map (notClash clashes) grove + modify' (\g -> g { currentGrove = grove'}) + +notClash :: S.Set Position -> Elf -> Elf +notClash clashes elf + | (elf ^. proposed) `S.member` clashes = elf & proposed .~ (elf ^. current) + | otherwise = elf + +-- the elves move + +moveElf :: Elf -> Elf +moveElf elf = elf & current .~ (elf ^. proposed) + +-- part 1 solution utilities + +findBounds :: Population -> (Position, Position) +findBounds grove = ((V2 minX minY), (V2 maxX maxY)) + where minX = fromJust $ minimumOf (folded . current . _x) grove + minY = fromJust $ minimumOf (folded . current . _y) grove + maxX = fromJust $ maximumOf (folded . current . _x) grove + maxY = fromJust $ maximumOf (folded . current . _y) grove + +countEmpty :: Population -> (Position, Position) -> Int +countEmpty grove bounds = (rangeSize bounds) - (S.size grove) + +-- Parse the input file + +mkGrove :: String -> Population +mkGrove text = S.fromList + [ Elf (V2 x y) (V2 x y) + | x <- [0..maxX], y <- [0..maxY] + , isElf x y + ] + where rows = reverse $ lines text + maxY = length rows - 1 + maxX = (length $ head rows) - 1 + isElf x y = ((rows !! y) !! x) == '#' -- 2.34.1 From 549425defbc1482abcef0e926094f0817842a4f5 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Tue, 3 Jan 2023 15:14:57 +0000 Subject: [PATCH 13/16] Added HashSet implementation --- advent-of-code22.cabal | 5 + advent23/Main.hs | 15 ++- advent23/MainUnordered.hs | 221 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 236 insertions(+), 5 deletions(-) create mode 100644 advent23/MainUnordered.hs diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 24f58ef..5a5315d 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -246,6 +246,11 @@ executable advent23original main-is: advent23/MainOriginal.hs build-depends: containers, linear, lens, mtl, multiset +executable advent23u + import: common-extensions, build-directives + main-is: advent23/MainUnordered.hs + build-depends: unordered-containers, hashable, linear, lens, mtl, multiset + executable advent23 import: common-extensions, build-directives main-is: advent23/Main.hs diff --git a/advent23/Main.hs b/advent23/Main.hs index 08eef6c..e604a96 100644 --- a/advent23/Main.hs +++ b/advent23/Main.hs @@ -9,6 +9,7 @@ import Data.Monoid import Control.Monad.State.Strict import Control.Monad.ST import qualified Data.Array.IArray as A +import Data.Array.IArray ((!)) import qualified Data.Array.MArray as M import Data.Array.ST import Data.Maybe @@ -73,6 +74,13 @@ simulateN n = simulateN (n - 1) simulateOnce = + do updateGrove + growGrove + updateDirections + updateCount + +updateGrove :: GroveState () +updateGrove = do grove <- gets currentGrove proposalsInf <- gets proposalDirections let proposals = take 4 proposalsInf @@ -85,9 +93,6 @@ simulateOnce = moveElves mPopulation return mPopulation modify' (\g -> g { currentGrove = newGrove}) - growGrove - updateDirections - updateCount growGrove = do grove <- gets currentGrove @@ -206,7 +211,7 @@ shrink grove findStrip stripDirection currentBounds where shiftBounds (b0, b1) (d0, d1) = (b0 ^+^ d0, b1 ^+^ d1) emptyStrip :: Population -> (Position, Position) -> Bool -emptyStrip grove strip = all isNothing $ fmap (grove A.!) $ range strip +emptyStrip grove strip = all isNothing $ fmap (grove !) $ range strip topStrip, bottomStrip, leftStrip, rightStrip :: (Position, Position) -> (Position, Position) topStrip (V2 minX _minY, V2 maxX maxY) = (V2 minX maxY, V2 maxX maxY) @@ -221,7 +226,7 @@ leftShrink = (V2 1 0, V2 0 0) rightShrink = (V2 0 0, V2 -1 0) countEmpty :: Population -> (Position, Position) -> Int -countEmpty grove bounds = length $ filter isNothing $ fmap (grove A.!) cells +countEmpty grove bounds = length $ filter isNothing $ fmap (grove !) cells where cells = range bounds -- Parse the input file diff --git a/advent23/MainUnordered.hs b/advent23/MainUnordered.hs new file mode 100644 index 0000000..a765b1a --- /dev/null +++ b/advent23/MainUnordered.hs @@ -0,0 +1,221 @@ +-- Writeup at https://work.njae.me.uk/2022/12/23/advent-of-code-2022-day-23/ + +-- import Debug.Trace + +import AoC +import qualified Data.HashSet as S +import Linear +import Control.Lens +import Data.Ix +import Data.Maybe +-- import Data.Char +import Data.Monoid +import Data.MultiSet as MS +import Control.Monad.State.Strict +import Data.Hashable + + +type Position = V2 Int -- r, c + +data Direction = North | South | West | East + deriving (Show, Eq, Ord, Enum, Bounded) + +data Elf = Elf { _current :: Position, _proposed :: Position} + -- deriving (Show, Eq, Ord) + -- deriving (Eq, Ord) +makeLenses ''Elf + +instance Show Elf where + show elf = "Elf {c= " ++ (show (elf ^. current)) + ++ ", p= " ++ (show (elf ^. proposed)) + ++ " -> " ++ (show (directionOfElf elf)) + ++ "}" + +instance Eq Elf where + e1 == e2 = (_current e1) == (_current e2) + +instance Ord Elf where + e1 `compare` e2 = (_current e1) `compare` (_current e2) + +instance Hashable Elf where + hashWithSalt s e = hashWithSalt s (e ^. current) + +type Population = S.HashSet Elf + +data Grove = Grove { currentGrove :: Population, proposalDirections :: [Direction], elapsedRounds :: Int} + deriving (Eq) + +instance Show Grove where + show grove = (show $ currentGrove grove) ++ ", " ++ (show $ take 4 $ proposalDirections grove) ++ ", e = " ++ (show $ elapsedRounds grove) + +type GroveState = State Grove + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- readFile dataFileName + let grove = Grove (mkGrove text) (cycle [North .. East]) 0 + -- print grove + -- print $ execState simulateOnce grove + -- print $ execState (simulateN 4) grove + print $ part1 grove + print $ part2 grove + +part1, part2 :: Grove -> Int +part1 grove = countEmpty grove' bounds + where grove' = currentGrove $ execState (simulateN 10) grove + bounds = findBounds grove' + +part2 grove = elapsedRounds grove' + where grove' = execState simulateToCompletion grove + +directionOfElf :: Elf -> Maybe Direction +directionOfElf elf + | delta == V2 0 1 = Just North + | delta == V2 0 -1 = Just South + | delta == V2 1 0 = Just East + | delta == V2 -1 0 = Just West + | otherwise = Nothing + where delta = (elf ^. proposed) ^-^ (elf ^. current) + +simulateToCompletion, simulateOnce, proposeMoves, removeClashes, moveElves, updateDirections, updateCount :: GroveState () +simulateToCompletion = + do oldGrove <- gets currentGrove + simulateOnce + newGrove <- gets currentGrove + if oldGrove == newGrove + then return () + else simulateToCompletion + +simulateN :: Int -> GroveState () +simulateN 0 = return () +simulateN n = + do simulateOnce + simulateN (n - 1) + +simulateOnce = + do proposeMoves + removeClashes + moveElves + updateDirections + updateCount + +proposeMoves = + do grove <- gets currentGrove + proposalsInf <- gets proposalDirections + let proposals = take 4 proposalsInf + let grove' = S.map (makeProposal grove proposals) grove + modify' (\g -> g { currentGrove = grove'}) + +removeClashes = + do grove <- gets currentGrove + let clashes = findClashes grove + stopClashingElves clashes + +moveElves = + do grove <- gets currentGrove + let grove' = S.map moveElf grove + modify' (\g -> g { currentGrove = grove'}) + +updateDirections = modify' (\g -> g { proposalDirections = tail (proposalDirections g)}) +updateCount = modify' (\g -> g { elapsedRounds = (elapsedRounds g) + 1}) + +-- position changing utilities + +anyNeighbour :: S.HashSet Position +anyNeighbour = S.fromList [ V2 dx dy + | dx <- [-1, 0, 1] + , dy <- [-1, 0, 1] + , not ((dx == 0) && (dy == 0)) + ] + +directionNeighbour :: Direction -> S.HashSet Position +directionNeighbour North = S.filter (\d -> d ^. _y == 1) anyNeighbour +directionNeighbour South = S.filter (\d -> d ^. _y == -1) anyNeighbour +directionNeighbour West = S.filter (\d -> d ^. _x == -1) anyNeighbour +directionNeighbour East = S.filter (\d -> d ^. _x == 1) anyNeighbour + +stepDelta :: Direction -> Position +stepDelta North = V2 0 1 +stepDelta South = V2 0 -1 +stepDelta West = V2 -1 0 +stepDelta East = V2 1 0 + +translateTo :: Position -> S.HashSet Position -> S.HashSet Position +translateTo here deltas = S.map (here ^+^) deltas + +noElves :: Population -> S.HashSet Position -> Bool +noElves elves tests = S.null $ S.intersection tests $ S.map _current elves + +-- get elves to make proposals + +isolated :: Population -> Elf -> Bool +isolated elves elf = noElves elves $ translateTo (elf ^. current) $ anyNeighbour + +nearby :: Population -> Elf -> Population +nearby elves elf = S.filter (\e -> (e ^. current) `S.member` nbrs) elves + where nbrs = translateTo (elf ^. current) $ anyNeighbour + +makeProposal :: Population -> [Direction] -> Elf -> Elf +makeProposal grove directions elf + | isolated localElves elf = elf + | otherwise = fromMaybe elf $ getFirst $ mconcat $ fmap First $ fmap (proposedStep localElves elf) directions + where localElves = nearby grove elf + +proposedStep :: Population -> Elf -> Direction -> Maybe Elf +proposedStep grove elf direction + | noElves grove interfering = Just $ elf & proposed .~ (here ^+^ (stepDelta direction)) + | otherwise = Nothing + where here = elf ^. current + interfering = translateTo here $ directionNeighbour direction + +-- find clashing elves and prevent them moving + +findClashes :: Population -> S.HashSet Position +findClashes grove = S.fromList $ MS.distinctElems $ MS.foldOccur ifMany MS.empty targets + where targets = MS.map _proposed $ MS.fromList $ S.toList grove + ifMany t n s + | n == 1 = s + | otherwise = MS.insert t s + +stopClashingElves :: S.HashSet Position -> GroveState () +stopClashingElves clashes = + do grove <- gets currentGrove + let grove' = S.map (notClash clashes) grove + modify' (\g -> g { currentGrove = grove'}) + +notClash :: S.HashSet Position -> Elf -> Elf +notClash clashes elf + | (elf ^. proposed) `S.member` clashes = elf & proposed .~ (elf ^. current) + | otherwise = elf + +-- the elves move + +moveElf :: Elf -> Elf +moveElf elf = elf & current .~ (elf ^. proposed) + +-- part 1 solution utilities + +findBounds :: Population -> (Position, Position) +findBounds grove = ((V2 minX minY), (V2 maxX maxY)) + where minX = fromJust $ minimumOf (folded . current . _x) grove + minY = fromJust $ minimumOf (folded . current . _y) grove + maxX = fromJust $ maximumOf (folded . current . _x) grove + maxY = fromJust $ maximumOf (folded . current . _y) grove + +countEmpty :: Population -> (Position, Position) -> Int +countEmpty grove bounds = (rangeSize bounds) - (S.size grove) + +-- Parse the input file + +mkGrove :: String -> Population +mkGrove text = S.fromList + [ Elf (V2 x y) (V2 x y) + | x <- [0..maxX], y <- [0..maxY] + , isElf x y + ] + where rows = reverse $ lines text + maxY = length rows - 1 + maxX = (length $ head rows) - 1 + isElf x y = ((rows !! y) !! x) == '#' -- 2.34.1 From 4087698696ed09477c3b5073f3d4d93d85c0a632 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Tue, 18 Jul 2023 15:22:56 +0100 Subject: [PATCH 14/16] Reworking day 16 --- advent-of-code22.cabal | 57 +++++ advent16/Main.hs | 252 ++++++++++++++------- advent16/MainBeam.hs | 362 +++++++++++++++++++++++++++++ advent16/MainCustomClosed.hs | 401 +++++++++++++++++++++++++++++++++ advent16/MainEstSort.hs | 352 +++++++++++++++++++++++++++++ advent16/MainOriginal.hs | 275 ++++++++++++++++++++++ advent16/MainOriginalNoBeam.hs | 275 ++++++++++++++++++++++ advent16/MainSPar.hs | 323 ++++++++++++++++++++++++++ advent16/MainSubsets.hs | 309 +++++++++++++++++++++++++ advent16/a16-solution.dot.png | Bin 0 -> 202269 bytes advent16/a16.dot | 94 ++++++++ 11 files changed, 2618 insertions(+), 82 deletions(-) create mode 100644 advent16/MainBeam.hs create mode 100644 advent16/MainCustomClosed.hs create mode 100644 advent16/MainEstSort.hs create mode 100644 advent16/MainOriginal.hs create mode 100644 advent16/MainOriginalNoBeam.hs create mode 100644 advent16/MainSPar.hs create mode 100644 advent16/MainSubsets.hs create mode 100644 advent16/a16-solution.dot.png create mode 100644 advent16/a16.dot diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 5a5315d..8a1b109 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -206,6 +206,63 @@ executable advent15prof -eventlog -rtsopts "-with-rtsopts=-N -p -s -hT -ls" +executable advent16original + import: common-extensions, build-directives + main-is: advent16/MainOriginal.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16originalnobeam + import: common-extensions, build-directives + main-is: advent16/MainOriginalNoBeam.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16sort + import: common-extensions, build-directives + main-is: advent16/MainEstSort.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16beam + import: common-extensions, build-directives + main-is: advent16/MainBeam.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16customclosed + import: common-extensions, build-directives + main-is: advent16/MainCustomClosed.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16spar + import: common-extensions, build-directives + main-is: advent16/MainSPar.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split, parallel, deepseq + +executable advent16sparprof + import: common-extensions, build-directives + main-is: advent16/MainSPar.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split, parallel, deepseq + ghc-options: -O2 + -Wall + -threaded + -eventlog + -fprof-auto + -rtsopts "-with-rtsopts=-N -p -s -hT -ls" + +executable advent16subsets + import: common-extensions, build-directives + main-is: advent16/MainSubsets.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + +executable advent16subsetsprof + import: common-extensions, build-directives + main-is: advent16/MainSubsets.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, split + ghc-options: -O2 + -Wall + -threaded + -eventlog + -fprof-auto + -rtsopts "-with-rtsopts=-N -p -s -hT -ls" + executable advent16 import: common-extensions, build-directives main-is: advent16/Main.hs diff --git a/advent16/Main.hs b/advent16/Main.hs index 7db601d..30d0843 100644 --- a/advent16/Main.hs +++ b/advent16/Main.hs @@ -1,6 +1,6 @@ -- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ --- import Debug.Trace +import Debug.Trace import AoC import Data.Text (Text) @@ -12,39 +12,44 @@ import qualified Data.Set as S import qualified Data.Sequence as Q import qualified Data.Map.Strict as M import Data.Map.Strict ((!)) -import Data.Sequence ((|>)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (|>), Seq((:|>)) ) import Data.List import Data.List.Split (chunksOf) import Data.Ord import Control.Monad.Reader import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) --- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty --- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) --- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) type RoomID = String +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + data Room = Room { _flowRate :: Int - , _tunnels :: [RoomID] + , _tunnels :: S.Set Tunnel } deriving (Eq, Show, Ord) makeLenses ''Room type Cave = M.Map RoomID Room -data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int} +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int , getSortedRooms :: [RoomID]} type CaveContext = Reader TimedCave data SingleSearchState = SingleSearchState { _currentRoom :: RoomID + , _currentTime :: Int , _sOpenValves :: S.Set RoomID } deriving (Eq, Show, Ord) makeLenses ''SingleSearchState data DoubleSearchState = DoubleSearchState { _personRoom :: RoomID + , _personTime :: Int , _elephantRoom :: RoomID + , _elephantTime :: Int , _dOpenValves :: S.Set RoomID } deriving (Eq, Show, Ord) makeLenses ''DoubleSearchState @@ -59,17 +64,24 @@ makeLenses ''Agendum type Agenda s = P.MaxPQueue Int (Agendum s) -type ExploredStates s = S.Set (s, Int, Int) +-- state, total flowed so far +type ExploredStates s = S.Set (s, Int) class (Eq s, Ord s, Show s) => SearchState s where emptySearchState :: RoomID -> s currentFlow :: s -> CaveContext Int + timeOf :: s -> Int successors :: s -> CaveContext (Q.Seq s) - estimateBenefit :: s -> Int -> CaveContext Int + -- estimateBenefit :: s -> Int -> CaveContext Int + estimateBenefit :: s -> CaveContext Int instance SearchState SingleSearchState where - emptySearchState startID = SingleSearchState { _currentRoom = startID, _sOpenValves = S.empty } + emptySearchState startID = SingleSearchState + { _currentRoom = startID + , _currentTime = 0 + , _sOpenValves = S.empty + } currentFlow state = do cave <- asks getCave @@ -77,29 +89,31 @@ instance SearchState SingleSearchState where let presentRooms = cave `M.restrictKeys` valves return $ sumOf (folded . flowRate) presentRooms + timeOf state = state ^. currentTime + successors state = do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit let here = state ^. currentRoom let opened = state ^. sOpenValves - succPairs <- personSuccessor here opened - let succStates = - [ SingleSearchState - { _currentRoom = r - , _sOpenValves = o - } - | (r, o) <- succPairs - ] - if isFF - then return $ Q.singleton state - else return $ Q.fromList succStates - - estimateBenefit here timeElapsed = + let now = state ^. currentTime + succs <- agentSuccessor now opened now here + let succStates = Q.fromList succs + if isFF || (Q.null succStates) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succStates + + estimateBenefit here = do cave <- asks getCave timeLimit <- asks getTimeLimit - let timeRemaining = timeLimit - (timeElapsed + 2) + let timeRemaining = timeLimit - (timeOf here) cf <- currentFlow here - let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate - let sortedClosedValves = sortOn Down closedValves + -- let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = sortOn Down closedValves + sortedValves <- asks getSortedRooms + let opened = here ^. sOpenValves + let sortedClosedValves = [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves return $ (cf * timeRemaining) + otherValveFlows @@ -107,44 +121,64 @@ instance SearchState SingleSearchState where instance SearchState DoubleSearchState where emptySearchState startID = DoubleSearchState { _personRoom = startID + , _personTime = 0 , _elephantRoom = startID + , _elephantTime = 0 , _dOpenValves = S.empty } currentFlow state = do cave <- asks getCave - let valves = state ^. dOpenValves - let presentRooms = cave `M.restrictKeys` valves - return $ sumOf (folded . flowRate) presentRooms + let valves = S.toList $ state ^. dOpenValves + return $ sum $ fmap (\v -> (cave ! v) ^. flowRate) valves + -- let presentRooms = cave `M.restrictKeys` valves + -- return $ sumOf (folded . flowRate) presentRooms + + timeOf state = min (state ^. personTime) (state ^. elephantTime) successors state = do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let opened = state ^. dOpenValves + let pNow = state ^. personTime + let eNow = state ^. elephantTime + let now = min pNow eNow let pHere = state ^. personRoom let eHere = state ^. elephantRoom - let opened = state ^. dOpenValves - pSuccPairs <- personSuccessor pHere opened - eSuccPairs <- personSuccessor eHere opened - let succStates = - [ DoubleSearchState - { _personRoom = p - , _elephantRoom = e - , _dOpenValves = S.union po eo - } - | (p, po) <- pSuccPairs - , (e, eo) <- eSuccPairs - ] - if isFF - then return $ Q.singleton state - else return $ Q.fromList succStates - - estimateBenefit here timeElapsed = + pNexts <- agentSuccessor now opened pNow pHere + eNexts <- agentSuccessor now opened eNow eHere + let nexts = [ state & personRoom .~ (p ^. currentRoom) + & personTime .~ (p ^. currentTime) + & elephantRoom .~ (e ^. currentRoom) + & elephantTime .~ (e ^. currentTime) + & dOpenValves %~ (S.union (p ^. sOpenValves) . S.union (e ^. sOpenValves)) + | p <- pNexts + , e <- eNexts + ] + let dedups = if pNow == eNow && pHere == eHere + then filter (\s -> (s ^. personRoom) < (s ^. elephantRoom)) nexts + -- else nexts + else filter (\s -> (s ^. personRoom) /= (s ^. elephantRoom)) nexts + -- let succStates = trace ("Succs: in " ++ (show state) ++ " out " ++ (show dedups)) (Q.fromList dedups) + let succStates = Q.fromList dedups + if isFF || (Q.null succStates) + then return $ Q.singleton (state & personTime .~ timeLimit & elephantTime .~ timeLimit) + else return succStates + + estimateBenefit here = do cave <- asks getCave timeLimit <- asks getTimeLimit - let timeRemaining = timeLimit - (timeElapsed + 2) + let timeRemaining = timeLimit - (timeOf here) cf <- currentFlow here - let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate - let sortedClosedValves = fmap sum $ chunksOf 2 $ sortOn Down closedValves + -- let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ {-# SCC estSort #-} sortOn Down closedValves + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ reverse $ sort closedValves -- no significant improvement + sortedValves <- asks getSortedRooms + let opened = here ^. dOpenValves + let sortedClosedValves = fmap sum $ chunksOf 2 $ [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + -- let otherValveFlows = timeRemaining * (sum closedValves) -- 8 minute runtime rather than 1:50 return $ (cf * timeRemaining) + otherValveFlows @@ -152,8 +186,11 @@ main :: IO () main = do dataFileName <- getDataFileName text <- TIO.readFile dataFileName - let cave = successfulParse text + let expandedCave = successfulParse text -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + let cave = compress expandedCave print $ part1 cave print $ part2 cave @@ -164,10 +201,14 @@ main = -- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int part1 cave = maybe 0 _benefit result - where result = runReader (searchCave "AA") (TimedCave cave 30) :: Maybe (Agendum SingleSearchState) + where result = runReader (searchCave "AA") (TimedCave cave 30 sortedRooms) :: Maybe (Agendum SingleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave part2 cave = maybe 0 _benefit result - where result = runReader (searchCave "AA") (TimedCave cave 26) :: Maybe (Agendum DoubleSearchState) + where result = runReader (searchCave "AA") (TimedCave cave 26 sortedRooms) :: Maybe (Agendum DoubleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + -- sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys cave searchCave :: SearchState s => String -> CaveContext (Maybe (Agendum s)) searchCave startRoom = @@ -177,13 +218,15 @@ searchCave startRoom = initAgenda :: SearchState s => String -> CaveContext (Agenda s) initAgenda startID = do let startState = emptySearchState startID - b <- estimateBenefit startState 0 + b <- estimateBenefit startState return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} aStar :: SearchState s => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) aStar agenda closed -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined - -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : len " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda) ++ " : trail " ++ (show $ _trail $ snd $ P.findMax agenda) ++ " : closed " ++ (show closed)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined | P.null agenda = return Nothing | otherwise = do let (_, currentAgendum) = P.findMax agenda @@ -191,15 +234,17 @@ aStar agenda closed nexts <- candidates currentAgendum closed let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width - let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 1000 newAgenda -- agenda beam width reachedGoal <- isGoal currentAgendum - let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + -- let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + let cl = (reached, currentAgendum ^. trailBenefit) if reachedGoal then return (Just currentAgendum) else if (cl `S.member` closed) then aStar (P.deleteMax agenda) closed - -- else aStar newAgenda (S.insert cl closed) - else aStar beamAgenda (S.insert cl closed) + else aStar newAgenda (S.insert cl closed) + -- else aStar beamAgenda (S.insert cl closed) candidates :: SearchState s => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) @@ -209,41 +254,65 @@ candidates agendum closed = let prevBenefit = agendum ^. trailBenefit succs <- successors candidate succAgs <- mapM (makeAgendum previous prevBenefit) succs - let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + -- let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs return nonloops -personSuccessor, openValveSuccessor, walkSuccessor :: RoomID -> S.Set RoomID -> CaveContext [(RoomID, S.Set RoomID)] -personSuccessor here opened = - do ovs <- openValveSuccessor here opened - ws <- walkSuccessor here opened - return (ovs ++ ws) -openValveSuccessor here opened - | here `S.member` opened = return [] - | otherwise = return [(here, S.insert here opened)] - -walkSuccessor here opened = - do cave <- asks getCave - let neighbours = (cave ! here) ^. tunnels - return [(n, opened) | n <- neighbours] +agentSuccessor :: Int -> S.Set RoomID -> Int -> RoomID -> CaveContext [SingleSearchState] +agentSuccessor now opened aTime here + | aTime /= now = return [SingleSearchState { _currentRoom = here, _currentTime = aTime, _sOpenValves = opened }] + | otherwise = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let moves = [ SingleSearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _sOpenValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let opens = if here `S.notMember` opened && (cave ! here) ^. flowRate > 0 + then [SingleSearchState { _currentRoom = here, _currentTime = aTime + 1, _sOpenValves = S.insert here opened }] + else [] + -- let nexts = moves ++ opens + let nexts = if null opens then moves else opens + let nexts' = if null nexts + then [ SingleSearchState + { _currentRoom = here + , _currentTime = timeLimit + , _sOpenValves = opened + } ] + else nexts + return nexts' makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) makeAgendum previous prevBenefit newState = - do predicted <- estimateBenefit newState (Q.length previous) - cf <- currentFlow newState + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) let newTrail = previous |> newState - let incurred = prevBenefit + cf + let incurred = prevBenefit + oldFlow return Agendum { _current = newState , _trail = newTrail , _trailBenefit = incurred , _benefit = incurred + predicted } +lastFlow :: SearchState s => Q.Seq s -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) isGoal :: SearchState s => Agendum s -> CaveContext Bool isGoal agendum = do timeLimit <- asks getTimeLimit - return $ Q.length (agendum ^. trail) == (timeLimit - 1) + let s = agendum ^. current + return $ (timeOf s) == timeLimit isFullFlow :: SearchState s => s -> CaveContext Bool isFullFlow state = @@ -252,21 +321,40 @@ isFullFlow state = let ff = sumOf (folded . flowRate) cave return (cf == ff) +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + -- Parse the input file caveP :: Parser Cave valveP :: Parser (RoomID, Room) roomP :: Parser Room -tunnelsP :: Parser [RoomID] -turnnelTextP :: Parser Text +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text caveP = M.fromList <$> valveP `sepBy` endOfLine valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP -roomP = roomify <$> (" has flow rate=" *> decimal) <*> (turnnelTextP *> tunnelsP) - where roomify v ts = Room {_flowRate = v, _tunnels = ts } -tunnelsP = (many1 letter) `sepBy` ", " -turnnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " successfulParse :: Text -> Cave successfulParse input = diff --git a/advent16/MainBeam.hs b/advent16/MainBeam.hs new file mode 100644 index 0000000..f82731c --- /dev/null +++ b/advent16/MainBeam.hs @@ -0,0 +1,362 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +-- import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (|>), Seq((:|>)) ) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + + +type RoomID = String + +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + +data Room = Room + { _flowRate :: Int + , _tunnels :: S.Set Tunnel + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int , getSortedRooms :: [RoomID]} + +type CaveContext = Reader TimedCave + +data SingleSearchState = SingleSearchState + { _currentRoom :: RoomID + , _currentTime :: Int + , _sOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +data DoubleSearchState = DoubleSearchState + { _personRoom :: RoomID + , _personTime :: Int + , _elephantRoom :: RoomID + , _elephantTime :: Int + , _dOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''DoubleSearchState + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +-- state, total flowed so far +type ExploredStates s = S.Set (s, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: RoomID -> s + currentFlow :: s -> CaveContext Int + timeOf :: s -> Int + successors :: s -> CaveContext (Q.Seq s) + -- estimateBenefit :: s -> Int -> CaveContext Int + estimateBenefit :: s -> CaveContext Int + +instance SearchState SingleSearchState where + emptySearchState startID = SingleSearchState + { _currentRoom = startID + , _currentTime = 0 + , _sOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. sOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + timeOf state = state ^. currentTime + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let here = state ^. currentRoom + let opened = state ^. sOpenValves + let now = state ^. currentTime + succs <- agentSuccessor now opened now here + let succStates = Q.fromList succs + if isFF || (Q.null succStates) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + -- let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = sortOn Down closedValves + sortedValves <- asks getSortedRooms + let opened = here ^. sOpenValves + let sortedClosedValves = [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +instance SearchState DoubleSearchState where + emptySearchState startID = DoubleSearchState + { _personRoom = startID + , _personTime = 0 + , _elephantRoom = startID + , _elephantTime = 0 + , _dOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = S.toList $ state ^. dOpenValves + return $ sum $ fmap (\v -> (cave ! v) ^. flowRate) valves + -- let presentRooms = cave `M.restrictKeys` valves + -- return $ sumOf (folded . flowRate) presentRooms + + timeOf state = min (state ^. personTime) (state ^. elephantTime) + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let opened = state ^. dOpenValves + let pNow = state ^. personTime + let eNow = state ^. elephantTime + let now = min pNow eNow + let pHere = state ^. personRoom + let eHere = state ^. elephantRoom + pNexts <- agentSuccessor now opened pNow pHere + eNexts <- agentSuccessor now opened eNow eHere + let nexts = [ state & personRoom .~ (p ^. currentRoom) + & personTime .~ (p ^. currentTime) + & elephantRoom .~ (e ^. currentRoom) + & elephantTime .~ (e ^. currentTime) + & dOpenValves %~ (S.union (p ^. sOpenValves) . S.union (e ^. sOpenValves)) + | p <- pNexts + , e <- eNexts + ] + let dedups = if pNow == eNow && pHere == eHere + then filter (\s -> (s ^. personRoom) < (s ^. elephantRoom)) nexts + -- else nexts + else filter (\s -> (s ^. personRoom) /= (s ^. elephantRoom)) nexts + -- let succStates = trace ("Succs: in " ++ (show state) ++ " out " ++ (show dedups)) (Q.fromList dedups) + let succStates = Q.fromList dedups + if isFF || (Q.null succStates) + then return $ Q.singleton (state & personTime .~ timeLimit & elephantTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + -- let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ {-# SCC estSort #-} sortOn Down closedValves + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ reverse $ sort closedValves -- no significant improvement + sortedValves <- asks getSortedRooms + let opened = here ^. dOpenValves + let sortedClosedValves = fmap sum $ chunksOf 2 $ [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + -- let otherValveFlows = timeRemaining * (sum closedValves) -- 8 minute runtime rather than 1:50 + return $ (cf * timeRemaining) + otherValveFlows + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let expandedCave = successfulParse text + -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + let cave = compress expandedCave + print $ part1 cave + print $ part2 cave + +-- part1 :: Cave -> Maybe (Agendum SingleSearchState) +-- part1 cave = runReader (searchCave "AA") (TimedCave cave 30) + +-- part2 :: Cave -> Maybe (Agendum DoubleSearchState) +-- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) + +part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int +part1 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 30 sortedRooms) :: Maybe (Agendum SingleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave +part2 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 26 sortedRooms) :: Maybe (Agendum DoubleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + -- sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys cave + +searchCave :: SearchState s => String -> CaveContext (Maybe (Agendum s)) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +initAgenda :: SearchState s => String -> CaveContext (Agenda s) +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: SearchState s => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + let beamAgenda = P.fromDescList $ P.take 1000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + -- let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + let cl = (reached, currentAgendum ^. trailBenefit) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + -- else aStar newAgenda (S.insert cl closed) + else aStar beamAgenda (S.insert cl closed) + + +candidates :: SearchState s => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + -- let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs + return nonloops + + +agentSuccessor :: Int -> S.Set RoomID -> Int -> RoomID -> CaveContext [SingleSearchState] +agentSuccessor now opened aTime here + | aTime /= now = return [SingleSearchState { _currentRoom = here, _currentTime = aTime, _sOpenValves = opened }] + | otherwise = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let moves = [ SingleSearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _sOpenValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let opens = if here `S.notMember` opened && (cave ! here) ^. flowRate > 0 + then [SingleSearchState { _currentRoom = here, _currentTime = aTime + 1, _sOpenValves = S.insert here opened }] + else [] + -- let nexts = moves ++ opens + let nexts = if null opens then moves else opens + let nexts' = if null nexts + then [ SingleSearchState + { _currentRoom = here + , _currentTime = timeLimit + , _sOpenValves = opened + } ] + else nexts + return nexts' + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) + let newTrail = previous |> newState + let incurred = prevBenefit + oldFlow + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +lastFlow :: SearchState s => Q.Seq s -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) + +isGoal :: SearchState s => Agendum s -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + let s = agendum ^. current + return $ (timeOf s) == timeLimit + +isFullFlow :: SearchState s => s -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainCustomClosed.hs b/advent16/MainCustomClosed.hs new file mode 100644 index 0000000..63fdf60 --- /dev/null +++ b/advent16/MainCustomClosed.hs @@ -0,0 +1,401 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (<|), (|>), Seq((:|>)) ) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + + +type RoomID = String + +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + +data Room = Room + { _flowRate :: Int + , _tunnels :: S.Set Tunnel + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int , getSortedRooms :: [RoomID]} + +type CaveContext = Reader TimedCave + +data SingleSearchState = SingleSearchState + { _currentRoom :: RoomID + , _currentTime :: Int + , _sOpenValves :: [RoomID] + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +data DoubleSearchState = DoubleSearchState + { _personRoom :: RoomID + , _personTime :: Int + , _elephantRoom :: RoomID + , _elephantTime :: Int + , _dOpenValves :: [RoomID] + } deriving (Eq, Show, Ord) +makeLenses ''DoubleSearchState + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +-- state, total flowed so far +-- type ExploredStates s = S.Set (s, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: RoomID -> s + currentFlow :: s -> CaveContext Int + timeOf :: s -> Int + successors :: s -> CaveContext (Q.Seq s) + -- estimateBenefit :: s -> Int -> CaveContext Int + estimateBenefit :: s -> CaveContext Int + + data ExploredStateKey s + -- type ExploredStates s + + mkExploredKey :: s -> (ExploredStateKey s) + +-- type ExploredStates s = M.Map (ExploredStateKey s) Int -- room/valves to time +type ExploredStates s = S.Set ((ExploredStateKey s), Int) -- room & valves, trail benefit + +instance SearchState SingleSearchState where + emptySearchState startID = SingleSearchState + { _currentRoom = startID + , _currentTime = 0 + , _sOpenValves = [] + } + + data ExploredStateKey SingleSearchState = SingleExploredStateKey RoomID [RoomID] -- current room and open valves + deriving (Show, Eq, Ord) + + mkExploredKey s = SingleExploredStateKey (s ^. currentRoom) (s ^. sOpenValves) + + currentFlow state = + do cave <- asks getCave + let valves = state ^. sOpenValves + let presentRooms = cave `M.restrictKeys` (S.fromList valves) + -- let presentRooms = M.filter (\v -> v `elem` valves) cave + return $ sumOf (folded . flowRate) presentRooms + + timeOf state = state ^. currentTime + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let here = state ^. currentRoom + let opened = state ^. sOpenValves + let now = state ^. currentTime + succs <- agentSuccessor now opened now here + let succStates = Q.fromList succs + if isFF || (Q.null succStates) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + -- let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = sortOn Down closedValves + sortedValves <- asks getSortedRooms + let opened = here ^. sOpenValves + let sortedClosedValves = [(cave ! v) ^. flowRate | v <- sortedValves, v `notElem` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +instance SearchState DoubleSearchState where + emptySearchState startID = DoubleSearchState + { _personRoom = startID + , _personTime = 0 + , _elephantRoom = startID + , _elephantTime = 0 + , _dOpenValves = [] + } + + data ExploredStateKey DoubleSearchState = DoubleExploredStateKey RoomID RoomID [RoomID] -- current room (person, elephant) and open valves + -- deriving (Show) + deriving (Show, Eq, Ord) + -- type ExploredStates DoubleSearchState = M.Map (DoubleExploredStateKey DoubleSearchState) Int -- room/valves to time + + mkExploredKey s = DoubleExploredStateKey minRoom maxRoom (s ^. dOpenValves) + where minRoom = min (s ^. personRoom) (s ^. elephantRoom) + maxRoom = max (s ^. personRoom) (s ^. elephantRoom) + + currentFlow state = + do cave <- asks getCave + -- let valves = S.toList $ state ^. dOpenValves + let valves = state ^. dOpenValves + return $ sum $ fmap (\v -> (cave ! v) ^. flowRate) valves + -- let presentRooms = cave `M.restrictKeys` valves + -- return $ sumOf (folded . flowRate) presentRooms + + timeOf state = min (state ^. personTime) (state ^. elephantTime) + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let opened = state ^. dOpenValves + let pNow = state ^. personTime + let eNow = state ^. elephantTime + let now = min pNow eNow + let pHere = state ^. personRoom + let eHere = state ^. elephantRoom + pNexts <- agentSuccessor now opened pNow pHere + eNexts <- agentSuccessor now opened eNow eHere + let nexts = [ state & personRoom .~ (p ^. currentRoom) + & personTime .~ (p ^. currentTime) + & elephantRoom .~ (e ^. currentRoom) + & elephantTime .~ (e ^. currentTime) + -- & dOpenValves %~ (S.union (p ^. sOpenValves) . S.union (e ^. sOpenValves)) + & dOpenValves .~ (union (union opened (p ^. sOpenValves)) (e ^. sOpenValves)) + | p <- pNexts + , e <- eNexts + ] + let dedups = if pNow == eNow && pHere == eHere + then filter (\s -> (s ^. personRoom) < (s ^. elephantRoom)) nexts + else nexts + -- let succStates = trace ("Succs: in " ++ (show state) ++ " out " ++ (show dedups)) (Q.fromList dedups) + let succStates = Q.fromList dedups + if isFF || (Q.null succStates) + then return $ Q.singleton (state & personTime .~ timeLimit & elephantTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + -- let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ {-# SCC estSort #-} sortOn Down closedValves + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ reverse $ sort closedValves -- no significant improvement + sortedValves <- asks getSortedRooms + let opened = here ^. dOpenValves + let sortedClosedValves = fmap sum $ chunksOf 2 $ [(cave ! v) ^. flowRate | v <- sortedValves, v `notElem` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + -- let otherValveFlows = timeRemaining * (sum closedValves) -- 8 minute runtime rather than 1:50 + return $ (cf * timeRemaining) + otherValveFlows + +-- instance Eq (ExploredStateKey DoubleSearchState) where +-- (DoubleExploredStateKey r1a r1b v1) == (DoubleExploredStateKey r2a r2b v2) = +-- -- ((r1a == r2a && r1b == r2b) || (r1a == r2b && r1b == r2a)) && v1 == v2 +-- ((min r1a r1b), (max r1a r1b), v1) == ((min r2a r2b), (max r2a r2b), v2) +-- -- data instance Ord DoubleExploredStateKey where +-- instance Ord (ExploredStateKey DoubleSearchState) where +-- (DoubleExploredStateKey r1a r1b v1) `compare` (DoubleExploredStateKey r2a r2b v2) = +-- ((min r1a r1b), (max r1a r1b), v1) `compare` ((min r2a r2b), (max r2a r2b), v2) + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let expandedCave = successfulParse text + -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + let cave = compress expandedCave + print $ part1 cave + print $ part2 cave + +-- part1 :: Cave -> Maybe (Agendum SingleSearchState) +-- part1 cave = runReader (searchCave "AA") (TimedCave cave 30) + +-- part2 :: Cave -> Maybe (Agendum DoubleSearchState) +-- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) + +part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int +part1 cave = maybe 0 _benefit result +-- part1 cave = result + where result = runReader (searchCave "AA") (TimedCave cave 30 sortedRooms) :: Maybe (Agendum SingleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave +part2 cave = maybe 0 _benefit result +-- part2 cave = result + where result = runReader (searchCave "AA") (TimedCave cave 26 sortedRooms) :: Maybe (Agendum DoubleSearchState) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + -- sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys cave + +searchCave :: ((Ord (ExploredStateKey s)), (Show (ExploredStateKey s)), SearchState s) => String -> CaveContext (Maybe (Agendum s)) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +initAgenda :: ((Ord (ExploredStateKey s)), (Show (ExploredStateKey s)), SearchState s) => String -> CaveContext (Agenda s) +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: ((Ord (ExploredStateKey s)), (Show (ExploredStateKey s)), SearchState s) => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda) ++ " : trail " ++ (show $ _trail $ snd $ P.findMax agenda) ++ " : closed " ++ (show closed)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 1000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + -- let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + -- let cl = (reached, currentAgendum ^. trailBenefit) + let cl = (mkExploredKey reached, currentAgendum ^. trailBenefit) + if reachedGoal + then return (Just currentAgendum) + else if (cl `elem` closed) + then aStar (P.deleteMax agenda) closed + else aStar newAgenda (S.insert cl closed) + + +candidates :: ((Ord (ExploredStateKey s)), SearchState s) => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + -- let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + -- let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs + let nonloops = Q.filter (\l -> ((mkExploredKey (l ^. current)), l ^. trailBenefit) `notElem` closed) succAgs + return nonloops + + +agentSuccessor :: Int -> [RoomID] -> Int -> RoomID -> CaveContext [SingleSearchState] +agentSuccessor now opened aTime here + | aTime /= now = return [SingleSearchState { _currentRoom = here, _currentTime = aTime, _sOpenValves = opened }] + | otherwise = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + -- let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let remaining = [ t + | t <- (S.toList ((cave ! here) ^. tunnels)) + , (t ^. tunnelTo) `notElem` opened + ] + let moves = [ SingleSearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _sOpenValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let moves' = ( SingleSearchState + { _currentRoom = here + , _currentTime = timeLimit + , _sOpenValves = opened + } + : moves) + let opens = if here `notElem` opened && (cave ! here) ^. flowRate > 0 + then [SingleSearchState { _currentRoom = here, _currentTime = aTime + 1, _sOpenValves = opened ++ [here] }] + else [] + -- let nexts = moves ++ opens + let nexts = if null opens then moves' else opens + return nexts + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) + let newTrail = previous |> newState + let incurred = prevBenefit + oldFlow + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +lastFlow :: SearchState s => Q.Seq s -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) + +isGoal :: SearchState s => Agendum s -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + let s = agendum ^. current + return $ (timeOf s) == timeLimit + +isFullFlow :: SearchState s => s -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainEstSort.hs b/advent16/MainEstSort.hs new file mode 100644 index 0000000..459a10b --- /dev/null +++ b/advent16/MainEstSort.hs @@ -0,0 +1,352 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +-- import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (|>), Seq((:|>)) ) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + + +type RoomID = String + +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + +data Room = Room + { _flowRate :: Int + , _tunnels :: S.Set Tunnel + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int } + +type CaveContext = Reader TimedCave + +data SingleSearchState = SingleSearchState + { _currentRoom :: RoomID + , _currentTime :: Int + , _sOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +data DoubleSearchState = DoubleSearchState + { _personRoom :: RoomID + , _personTime :: Int + , _elephantRoom :: RoomID + , _elephantTime :: Int + , _dOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''DoubleSearchState + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +-- state, total flowed so far +type ExploredStates s = S.Set (s, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: RoomID -> s + currentFlow :: s -> CaveContext Int + timeOf :: s -> Int + successors :: s -> CaveContext (Q.Seq s) + -- estimateBenefit :: s -> Int -> CaveContext Int + estimateBenefit :: s -> CaveContext Int + +instance SearchState SingleSearchState where + emptySearchState startID = SingleSearchState + { _currentRoom = startID + , _currentTime = 0 + , _sOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. sOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + timeOf state = state ^. currentTime + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let here = state ^. currentRoom + let opened = state ^. sOpenValves + let now = state ^. currentTime + succs <- agentSuccessor now opened now here + let succStates = Q.fromList succs + if isFF || (Q.null succStates) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + let sortedClosedValves = sortOn Down closedValves + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +instance SearchState DoubleSearchState where + emptySearchState startID = DoubleSearchState + { _personRoom = startID + , _personTime = 0 + , _elephantRoom = startID + , _elephantTime = 0 + , _dOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = S.toList $ state ^. dOpenValves + return $ sum $ fmap (\v -> (cave ! v) ^. flowRate) valves + -- let presentRooms = cave `M.restrictKeys` valves + -- return $ sumOf (folded . flowRate) presentRooms + + timeOf state = min (state ^. personTime) (state ^. elephantTime) + + successors state = + do isFF <- isFullFlow state + -- cave <- asks getCave + timeLimit <- asks getTimeLimit + let opened = state ^. dOpenValves + let pNow = state ^. personTime + let eNow = state ^. elephantTime + let now = min pNow eNow + let pHere = state ^. personRoom + let eHere = state ^. elephantRoom + pNexts <- agentSuccessor now opened pNow pHere + eNexts <- agentSuccessor now opened eNow eHere + let nexts = [ state & personRoom .~ (p ^. currentRoom) + & personTime .~ (p ^. currentTime) + & elephantRoom .~ (e ^. currentRoom) + & elephantTime .~ (e ^. currentTime) + & dOpenValves %~ (S.union (p ^. sOpenValves) . S.union (e ^. sOpenValves)) + | p <- pNexts + , e <- eNexts + ] + let dedups = if pNow == eNow && pHere == eHere + then filter (\s -> (s ^. personRoom) < (s ^. elephantRoom)) nexts + else nexts + -- let succStates = trace ("Succs: in " ++ (show state) ++ " out " ++ (show dedups)) (Q.fromList dedups) + let succStates = Q.fromList dedups + if isFF || (Q.null succStates) + then return $ Q.singleton (state & personTime .~ timeLimit & elephantTime .~ timeLimit) + else return succStates + + estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + let sortedClosedValves = fmap sum $ chunksOf 2 $ {-# SCC estSort #-} sortOn Down closedValves + -- let sortedClosedValves = fmap sum $ chunksOf 2 $ reverse $ sort closedValves -- no significant improvement + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + -- let otherValveFlows = timeRemaining * (sum closedValves) -- 8 minute runtime rather than 1:50 + return $ (cf * timeRemaining) + otherValveFlows + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let expandedCave = successfulParse text + -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + let cave = compress expandedCave + print $ part1 cave + print $ part2 cave + +-- part1 :: Cave -> Maybe (Agendum SingleSearchState) +-- part1 cave = runReader (searchCave "AA") (TimedCave cave 30) + +-- part2 :: Cave -> Maybe (Agendum DoubleSearchState) +-- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) + +part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int +part1 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 30) :: Maybe (Agendum SingleSearchState) +part2 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 26) :: Maybe (Agendum DoubleSearchState) + +searchCave :: SearchState s => String -> CaveContext (Maybe (Agendum s)) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +initAgenda :: SearchState s => String -> CaveContext (Agenda s) +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: SearchState s => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 1000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + -- let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + let cl = (reached, currentAgendum ^. trailBenefit) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + else aStar newAgenda (S.insert cl closed) + -- else aStar beamAgenda (S.insert cl closed) + + +candidates :: SearchState s => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + -- let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs + return nonloops + + +agentSuccessor :: Int -> S.Set RoomID -> Int -> RoomID -> CaveContext [SingleSearchState] +agentSuccessor now opened aTime here + | aTime /= now = return [SingleSearchState { _currentRoom = here, _currentTime = aTime, _sOpenValves = opened }] + | otherwise = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let moves = [ SingleSearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _sOpenValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let opens = if here `S.notMember` opened && (cave ! here) ^. flowRate > 0 + then [SingleSearchState { _currentRoom = here, _currentTime = aTime + 1, _sOpenValves = S.insert here opened }] + else [] + -- let nexts = moves ++ opens + let nexts = if null opens then moves else opens + let nexts' = if null nexts + then [ SingleSearchState + { _currentRoom = here + , _currentTime = timeLimit + , _sOpenValves = opened + } ] + else nexts + return nexts' + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) + let newTrail = previous |> newState + let incurred = prevBenefit + oldFlow + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +lastFlow :: SearchState s => Q.Seq s -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) + +isGoal :: SearchState s => Agendum s -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + let s = agendum ^. current + return $ (timeOf s) == timeLimit + +isFullFlow :: SearchState s => s -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainOriginal.hs b/advent16/MainOriginal.hs new file mode 100644 index 0000000..3000671 --- /dev/null +++ b/advent16/MainOriginal.hs @@ -0,0 +1,275 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +-- import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import Data.Sequence ((|>)) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + +-- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty +-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) +-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) + +type RoomID = String + +data Room = Room + { _flowRate :: Int + , _tunnels :: [RoomID] + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int} + +type CaveContext = Reader TimedCave + +data SingleSearchState = SingleSearchState + { _currentRoom :: RoomID + , _sOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +data DoubleSearchState = DoubleSearchState + { _personRoom :: RoomID + , _elephantRoom :: RoomID + , _dOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''DoubleSearchState + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +type ExploredStates s = S.Set (s, Int, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: RoomID -> s + currentFlow :: s -> CaveContext Int + successors :: s -> CaveContext (Q.Seq s) + estimateBenefit :: s -> Int -> CaveContext Int + +instance SearchState SingleSearchState where + emptySearchState startID = SingleSearchState { _currentRoom = startID, _sOpenValves = S.empty } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. sOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + successors state = + do isFF <- isFullFlow state + let here = state ^. currentRoom + let opened = state ^. sOpenValves + succPairs <- personSuccessor here opened + let succStates = + [ SingleSearchState + { _currentRoom = r + , _sOpenValves = o + } + | (r, o) <- succPairs + ] + if isFF + then return $ Q.singleton state + else return $ Q.fromList succStates + + estimateBenefit here timeElapsed = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 2) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + let sortedClosedValves = sortOn Down closedValves + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +instance SearchState DoubleSearchState where + emptySearchState startID = DoubleSearchState + { _personRoom = startID + , _elephantRoom = startID + , _dOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. dOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + successors state = + do isFF <- isFullFlow state + let pHere = state ^. personRoom + let eHere = state ^. elephantRoom + let opened = state ^. dOpenValves + pSuccPairs <- personSuccessor pHere opened + eSuccPairs <- personSuccessor eHere opened + let succStates = + [ DoubleSearchState + { _personRoom = p + , _elephantRoom = e + , _dOpenValves = S.union po eo + } + | (p, po) <- pSuccPairs + , (e, eo) <- eSuccPairs + ] + if isFF + then return $ Q.singleton state + else return $ Q.fromList succStates + + estimateBenefit here timeElapsed = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 2) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + let sortedClosedValves = fmap sum $ chunksOf 2 $ sortOn Down closedValves + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let cave = successfulParse text + -- print cave + print $ part1 cave + print $ part2 cave + +-- part1 :: Cave -> Maybe (Agendum SingleSearchState) +-- part1 cave = runReader (searchCave "AA") (TimedCave cave 30) + +-- part2 :: Cave -> Maybe (Agendum DoubleSearchState) +-- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) + +part1, part2 :: Cave -> Int +part1 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 30) :: Maybe (Agendum SingleSearchState) +part2 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 26) :: Maybe (Agendum DoubleSearchState) + +searchCave :: SearchState s => String -> CaveContext (Maybe (Agendum s)) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +initAgenda :: SearchState s => String -> CaveContext (Agenda s) +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState 0 + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: SearchState s => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : len " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + -- else aStar newAgenda (S.insert cl closed) + else aStar beamAgenda (S.insert cl closed) + + +candidates :: SearchState s => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + return nonloops + +personSuccessor, openValveSuccessor, walkSuccessor :: RoomID -> S.Set RoomID -> CaveContext [(RoomID, S.Set RoomID)] +personSuccessor here opened = + do ovs <- openValveSuccessor here opened + ws <- walkSuccessor here opened + return (ovs ++ ws) + +openValveSuccessor here opened + | here `S.member` opened = return [] + | otherwise = return [(here, S.insert here opened)] + +walkSuccessor here opened = + do cave <- asks getCave + let neighbours = (cave ! here) ^. tunnels + return [(n, opened) | n <- neighbours] + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState (Q.length previous) + cf <- currentFlow newState + let newTrail = previous |> newState + let incurred = prevBenefit + cf + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + + +isGoal :: SearchState s => Agendum s -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + return $ Q.length (agendum ^. trail) == (timeLimit - 1) + +isFullFlow :: SearchState s => s -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser [RoomID] +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = roomify <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + where roomify v ts = Room {_flowRate = v, _tunnels = ts } +tunnelsP = (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainOriginalNoBeam.hs b/advent16/MainOriginalNoBeam.hs new file mode 100644 index 0000000..b074d93 --- /dev/null +++ b/advent16/MainOriginalNoBeam.hs @@ -0,0 +1,275 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +-- import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import Data.Sequence ((|>)) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + +-- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty +-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) +-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) + +type RoomID = String + +data Room = Room + { _flowRate :: Int + , _tunnels :: [RoomID] + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int} + +type CaveContext = Reader TimedCave + +data SingleSearchState = SingleSearchState + { _currentRoom :: RoomID + , _sOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +data DoubleSearchState = DoubleSearchState + { _personRoom :: RoomID + , _elephantRoom :: RoomID + , _dOpenValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''DoubleSearchState + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +type ExploredStates s = S.Set (s, Int, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: RoomID -> s + currentFlow :: s -> CaveContext Int + successors :: s -> CaveContext (Q.Seq s) + estimateBenefit :: s -> Int -> CaveContext Int + +instance SearchState SingleSearchState where + emptySearchState startID = SingleSearchState { _currentRoom = startID, _sOpenValves = S.empty } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. sOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + successors state = + do isFF <- isFullFlow state + let here = state ^. currentRoom + let opened = state ^. sOpenValves + succPairs <- personSuccessor here opened + let succStates = + [ SingleSearchState + { _currentRoom = r + , _sOpenValves = o + } + | (r, o) <- succPairs + ] + if isFF + then return $ Q.singleton state + else return $ Q.fromList succStates + + estimateBenefit here timeElapsed = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 2) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. sOpenValves)) ^.. folded . flowRate + let sortedClosedValves = sortOn Down closedValves + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +instance SearchState DoubleSearchState where + emptySearchState startID = DoubleSearchState + { _personRoom = startID + , _elephantRoom = startID + , _dOpenValves = S.empty + } + + currentFlow state = + do cave <- asks getCave + let valves = state ^. dOpenValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + + successors state = + do isFF <- isFullFlow state + let pHere = state ^. personRoom + let eHere = state ^. elephantRoom + let opened = state ^. dOpenValves + pSuccPairs <- personSuccessor pHere opened + eSuccPairs <- personSuccessor eHere opened + let succStates = + [ DoubleSearchState + { _personRoom = p + , _elephantRoom = e + , _dOpenValves = S.union po eo + } + | (p, po) <- pSuccPairs + , (e, eo) <- eSuccPairs + ] + if isFF + then return $ Q.singleton state + else return $ Q.fromList succStates + + estimateBenefit here timeElapsed = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 2) + cf <- currentFlow here + let closedValves = (cave `M.withoutKeys` (here ^. dOpenValves)) ^.. folded . flowRate + let sortedClosedValves = fmap sum $ chunksOf 2 $ sortOn Down closedValves + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let cave = successfulParse text + -- print cave + print $ part1 cave + print $ part2 cave + +-- part1 :: Cave -> Maybe (Agendum SingleSearchState) +-- part1 cave = runReader (searchCave "AA") (TimedCave cave 30) + +-- part2 :: Cave -> Maybe (Agendum DoubleSearchState) +-- part2 cave = runReader (searchCave "AA") (TimedCave cave 26) + +part1, part2 :: Cave -> Int +part1 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 30) :: Maybe (Agendum SingleSearchState) +part2 cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave 26) :: Maybe (Agendum DoubleSearchState) + +searchCave :: SearchState s => String -> CaveContext (Maybe (Agendum s)) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +initAgenda :: SearchState s => String -> CaveContext (Agenda s) +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState 0 + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: SearchState s => Agenda s -> ExploredStates s -> CaveContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : len " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + else aStar newAgenda (S.insert cl closed) + -- else aStar beamAgenda (S.insert cl closed) + + +candidates :: SearchState s => Agendum s -> ExploredStates s -> CaveContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + return nonloops + +personSuccessor, openValveSuccessor, walkSuccessor :: RoomID -> S.Set RoomID -> CaveContext [(RoomID, S.Set RoomID)] +personSuccessor here opened = + do ovs <- openValveSuccessor here opened + ws <- walkSuccessor here opened + return (ovs ++ ws) + +openValveSuccessor here opened + | here `S.member` opened = return [] + | otherwise = return [(here, S.insert here opened)] + +walkSuccessor here opened = + do cave <- asks getCave + let neighbours = (cave ! here) ^. tunnels + return [(n, opened) | n <- neighbours] + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> CaveContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState (Q.length previous) + cf <- currentFlow newState + let newTrail = previous |> newState + let incurred = prevBenefit + cf + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + + +isGoal :: SearchState s => Agendum s -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + return $ Q.length (agendum ^. trail) == (timeLimit - 1) + +isFullFlow :: SearchState s => s -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser [RoomID] +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = roomify <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + where roomify v ts = Room {_flowRate = v, _tunnels = ts } +tunnelsP = (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainSPar.hs b/advent16/MainSPar.hs new file mode 100644 index 0000000..d3be5ec --- /dev/null +++ b/advent16/MainSPar.hs @@ -0,0 +1,323 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (|>), Seq((:|>)) ) +import Data.List +import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import Control.Parallel.Strategies + + +type RoomID = String + +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + +data Room = Room + { _flowRate :: Int + , _tunnels :: S.Set Tunnel + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int , getSortedRooms :: [RoomID]} + +type CaveContext = Reader TimedCave + +data SearchState = SearchState + { _currentRoom :: RoomID + , _currentTime :: Int + , _openValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SearchState + +data Agendum = + Agendum { _current :: SearchState + , _trail :: Q.Seq SearchState + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda = P.MaxPQueue Int Agendum + +-- state, total flowed so far +type ExploredStates = S.Set (SearchState, Int) + +type PartSolutions = M.Map (S.Set RoomID) Int + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let expandedCave = successfulParse text + -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + -- putStrLn $ dotify expandedCave + let cave = compress expandedCave + print $ part1 cave + print $ part2 cave + +-- dotify cave = "graph G {\n" ++ (unlines $ concat $ M.elems $ M.mapWithKey showCRoom cave) ++ "\n}\n" +-- where showCRoom roomID room = filter (not . null) ((showCRoomShape roomID room) : (showCRoomLinks roomID room)) + +-- showCRoomShape roomID room +-- | room ^. flowRate > 0 = roomID ++ " [fillcolor=grey label=\"" ++ roomID ++ ": " ++ (show $ room ^. flowRate) ++ "\"];" +-- | otherwise = "" + +-- showCRoomLinks roomID room = [roomID ++ " -- " ++ (t ^. tunnelTo) ++ ";" | t <- S.toList $ room ^. tunnels, (t ^. tunnelTo) > roomID ] + +part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int +part1 cave = runSearch 30 cave +part2 cave = maximum (fmap maximum chunkSolns `using` parList rdeepseq) + where rawSolutions = runSearchAll 26 cave + solutionList = M.toList rawSolutions + combinations = [ fp + fe + | (p, fp) <- solutionList + , (e, fe) <- solutionList + , p < e + , S.disjoint p e + ] + chunkSolns = chunksOf 10000 combinations + +includeAgendum :: PartSolutions -> Agendum -> CaveContext PartSolutions +includeAgendum results agendum = + do cf <- currentFlow (agendum ^. current) + timeLimit <- asks getTimeLimit + let timeLeft = timeLimit - timeOf (agendum ^. current) + let remainingFlow = cf * timeLeft + let totalFlow = remainingFlow + agendum ^. trailBenefit + let visitedSet = agendum ^. current . openValves + let currentBest = M.findWithDefault 0 visitedSet results + if totalFlow > currentBest + then return (M.insert visitedSet totalFlow results) + else return results + +runSearch :: Int -> Cave -> Int +runSearch timeLimit cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave timeLimit sortedRooms) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + +runSearchAll :: Int -> Cave -> PartSolutions +runSearchAll timeLimit cave = result + where result = runReader (searchCaveAll "AA") (TimedCave cave timeLimit sortedRooms) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + + +searchCave :: String -> CaveContext (Maybe Agendum) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +searchCaveAll :: String -> CaveContext PartSolutions +searchCaveAll startRoom = + do agenda <- initAgenda startRoom + allSolutions agenda S.empty M.empty + +initAgenda :: String -> CaveContext Agenda +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: Agenda -> ExploredStates -> CaveContext (Maybe Agendum) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda) ++ " : trail " ++ (show $ _trail $ snd $ P.findMax agenda) ++ " : closed " ++ (show closed)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + else aStar newAgenda (S.insert cl closed) + +allSolutions :: Agenda -> ExploredStates -> PartSolutions -> CaveContext PartSolutions +allSolutions agenda closed foundSolutions + | P.null agenda = return foundSolutions + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit) + newFoundSolutions <- includeAgendum foundSolutions currentAgendum + if reachedGoal + then allSolutions (P.deleteMax agenda) closed newFoundSolutions + else if (cl `S.member` closed) + then allSolutions (P.deleteMax agenda) closed foundSolutions + else allSolutions newAgenda (S.insert cl closed) newFoundSolutions + + +candidates :: Agendum -> ExploredStates -> CaveContext (Q.Seq Agendum) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs + return nonloops + +emptySearchState :: RoomID -> SearchState +emptySearchState startID = SearchState + { _currentRoom = startID + , _currentTime = 0 + , _openValves = S.empty + } + +currentFlow :: SearchState -> CaveContext Int +currentFlow state = + do cave <- asks getCave + let valves = state ^. openValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + +timeOf :: SearchState -> Int +timeOf state = state ^. currentTime + +successors :: SearchState -> CaveContext (Q.Seq SearchState) +successors state = + do isFF <- isFullFlow state + cave <- asks getCave + timeLimit <- asks getTimeLimit + let here = state ^. currentRoom + let opened = state ^. openValves + let now = state ^. currentTime + let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let moves = [ SearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _openValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let opens = if here `S.notMember` opened && (cave ! here) ^. flowRate > 0 && now < timeLimit + then [SearchState { _currentRoom = here, _currentTime = now + 1, _openValves = S.insert here opened }] + else [] + let nexts = if null opens then moves else opens + let nexts' = if null nexts + then [ SearchState + { _currentRoom = here + , _currentTime = timeLimit + , _openValves = opened + } ] + else nexts + let succs = Q.fromList nexts' + if isFF || (Q.null succs) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succs + + +estimateBenefit :: SearchState -> CaveContext Int +estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + sortedValves <- asks getSortedRooms + let opened = here ^. openValves + let sortedClosedValves = [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + +makeAgendum :: Q.Seq SearchState -> Int -> SearchState -> CaveContext Agendum +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) + let newTrail = previous |> newState + let incurred = prevBenefit + oldFlow + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +lastFlow :: Q.Seq SearchState -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) + +isGoal :: Agendum -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + let s = agendum ^. current + return $ (timeOf s) == timeLimit + +isFullFlow :: SearchState -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/MainSubsets.hs b/advent16/MainSubsets.hs new file mode 100644 index 0000000..b927188 --- /dev/null +++ b/advent16/MainSubsets.hs @@ -0,0 +1,309 @@ +-- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ + +import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +-- import Data.Sequence ((|>), Seq((:|>)), ViewR ((:>))) +import Data.Sequence ( (|>), Seq((:|>)) ) +import Data.List +-- import Data.List.Split (chunksOf) +import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) + +type RoomID = String + +data Tunnel = Tunnel { _tunnelTo :: RoomID, _tunnelLength :: Int} + deriving (Eq, Show, Ord) +makeLenses ''Tunnel + +data Room = Room + { _flowRate :: Int + , _tunnels :: S.Set Tunnel + } deriving (Eq, Show, Ord) +makeLenses ''Room + +type Cave = M.Map RoomID Room +data TimedCave = TimedCave { getCave :: Cave, getTimeLimit :: Int , getSortedRooms :: [RoomID]} + +type CaveContext = Reader TimedCave + +data SearchState = SearchState + { _currentRoom :: RoomID + , _currentTime :: Int + , _openValves :: S.Set RoomID + } deriving (Eq, Show, Ord) +makeLenses ''SearchState + +data Agendum = + Agendum { _current :: SearchState + , _trail :: Q.Seq SearchState + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda = P.MaxPQueue Int Agendum + +-- state, total flowed so far +type ExploredStates = S.Set (SearchState, Int) + +type PartSolutions = M.Map (S.Set RoomID) Int + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let expandedCave = successfulParse text + -- print cave + -- print $ reachableFrom cave [Tunnel "AA" 0] S.empty [] + -- print $ compress cave + let cave = compress expandedCave + print $ part1 cave + print $ part2 cave + +part1, part2 :: Cave -> Int +-- part1 :: Cave -> Int +part1 cave = runSearch 30 cave +part2 cave = maximum combinations + where rawSolutions = runSearchAll 26 cave + solutionList = M.toList rawSolutions + combinations = [ (f1 + f2) + | (p, f1) <- solutionList + , (e, f2) <- solutionList + , p < e + , S.disjoint p e + ] + +includeAgendum :: PartSolutions -> Agendum -> CaveContext PartSolutions +includeAgendum results agendum = + do cf <- currentFlow (agendum ^. current) + timeLimit <- asks getTimeLimit + let timeLeft = timeLimit - timeOf (agendum ^. current) + let remainingFlow = cf * timeLeft + let totalFlow = remainingFlow + agendum ^. trailBenefit + let visitedSet = agendum ^. current . openValves + let currentBest = M.findWithDefault 0 visitedSet results + if totalFlow > currentBest + then return (M.insert visitedSet totalFlow results) + else return results + +runSearch :: Int -> Cave -> Int +runSearch timeLimit cave = maybe 0 _benefit result + where result = runReader (searchCave "AA") (TimedCave cave timeLimit sortedRooms) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + +runSearchAll :: Int -> Cave -> PartSolutions +runSearchAll timeLimit cave = result + where result = runReader (searchCaveAll "AA") (TimedCave cave timeLimit sortedRooms) + sortedRooms = sortOn (\r -> Down $ (cave ! r) ^. flowRate ) $ M.keys $ M.filter (\r -> r ^. flowRate > 0) cave + + +searchCave :: String -> CaveContext (Maybe Agendum) +searchCave startRoom = + do agenda <- initAgenda startRoom + aStar agenda S.empty + +searchCaveAll :: String -> CaveContext PartSolutions +searchCaveAll startRoom = + do agenda <- initAgenda startRoom + allSolutions agenda S.empty M.empty + +initAgenda :: String -> CaveContext Agenda +initAgenda startID = + do let startState = emptySearchState startID + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: Agenda -> ExploredStates -> CaveContext (Maybe Agendum) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " : foundFlow " ++ (show $ _trailBenefit $ snd $ P.findMax agenda) ++ " : trail " ++ (show $ _trail $ snd $ P.findMax agenda) ++ " : closed " ++ (show closed)) False = undefined + -- | trace ("Peeping " ++ (show $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + else aStar newAgenda (S.insert cl closed) + +allSolutions :: Agenda -> ExploredStates -> PartSolutions -> CaveContext PartSolutions +allSolutions agenda closed foundSolutions + | P.null agenda = return foundSolutions + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit) + newFoundSolutions <- includeAgendum foundSolutions currentAgendum + if reachedGoal + then allSolutions (P.deleteMax agenda) closed newFoundSolutions + else if (cl `S.member` closed) + then allSolutions (P.deleteMax agenda) closed foundSolutions + else allSolutions newAgenda (S.insert cl closed) newFoundSolutions + + +candidates :: Agendum -> ExploredStates -> CaveContext (Q.Seq Agendum) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit) `S.notMember` closed) succAgs + return nonloops + +emptySearchState :: RoomID -> SearchState +emptySearchState startID = SearchState + { _currentRoom = startID + , _currentTime = 0 + , _openValves = S.empty + } + +currentFlow :: SearchState -> CaveContext Int +currentFlow state = + do cave <- asks getCave + let valves = state ^. openValves + let presentRooms = cave `M.restrictKeys` valves + return $ sumOf (folded . flowRate) presentRooms + +timeOf :: SearchState -> Int +timeOf state = state ^. currentTime + +successors :: SearchState -> CaveContext (Q.Seq SearchState) +successors state = + do isFF <- isFullFlow state + cave <- asks getCave + timeLimit <- asks getTimeLimit + let here = state ^. currentRoom + let opened = state ^. openValves + let now = state ^. currentTime + let remaining = S.toList $ S.filter (\t -> (t ^. tunnelTo) `S.notMember` opened) ((cave ! here) ^. tunnels) + let moves = [ SearchState + { _currentRoom = (t ^. tunnelTo) + , _currentTime = now + (t ^. tunnelLength) + , _openValves = opened + } + | t <- remaining + , now + (t ^. tunnelLength) <= timeLimit + ] + let opens = if here `S.notMember` opened && (cave ! here) ^. flowRate > 0 && now < timeLimit + then [SearchState { _currentRoom = here, _currentTime = now + 1, _openValves = S.insert here opened }] + else [] + let nexts = if null opens then moves else opens + let nexts' = if null nexts + then [ SearchState + { _currentRoom = here + , _currentTime = timeLimit + , _openValves = opened + } ] + else nexts + let succs = Q.fromList nexts' + if isFF || (Q.null succs) + then return $ Q.singleton (state & currentTime .~ timeLimit) + else return succs + +estimateBenefit :: SearchState -> CaveContext Int +estimateBenefit here = + do cave <- asks getCave + timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeOf here) + cf <- currentFlow here + sortedValves <- asks getSortedRooms + let opened = here ^. openValves + let sortedClosedValves = [(cave ! v) ^. flowRate | v <- sortedValves, v `S.notMember` opened] + let otherValveFlows = sum $ zipWith (*) [timeRemaining, (timeRemaining - 2) .. 0] sortedClosedValves + return $ (cf * timeRemaining) + otherValveFlows + +makeAgendum :: Q.Seq SearchState -> Int -> SearchState -> CaveContext Agendum +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState -- (Q.length previous) + -- cf <- currentFlow newState + oldFlow <- lastFlow previous (timeOf newState) + let newTrail = previous |> newState + let incurred = prevBenefit + oldFlow + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +lastFlow :: Q.Seq SearchState -> Int -> CaveContext Int +lastFlow Q.Empty _ = return 0 +lastFlow (_ :|> previous) newTime = + do cf <- currentFlow previous + let dt = newTime - (timeOf previous) + return (cf * dt) + +isGoal :: Agendum -> CaveContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + let s = agendum ^. current + return $ (timeOf s) == timeLimit + +isFullFlow :: SearchState -> CaveContext Bool +isFullFlow state = + do cave <- asks getCave + cf <- currentFlow state + let ff = sumOf (folded . flowRate) cave + return (cf == ff) + +compress :: Cave -> Cave +compress cave = M.mapWithKey (compressRoom cave) cave + +compressRoom :: Cave -> RoomID -> Room -> Room +compressRoom cave here room = room & tunnels .~ t' + where t' = reachableFrom cave [Tunnel here 0] S.empty S.empty + +reachableFrom :: Cave -> [Tunnel] -> S.Set RoomID -> S.Set Tunnel -> S.Set Tunnel +reachableFrom _ [] _ routes = routes +reachableFrom cave (tunnel@(Tunnel here len):boundary) found routes + | here `S.member` found = reachableFrom cave boundary found routes + | otherwise = reachableFrom cave (boundary ++ (S.toList legs)) (S.insert here found) routes' + where exits = (cave ! here) ^. tunnels + exits' = S.filter (\t -> (t ^. tunnelTo) `S.notMember` found) exits + legs = S.map (\t -> t & tunnelLength .~ (len + 1)) exits' + routes' = if (len == 0) || ((cave ! here) ^. flowRate) == 0 + then routes + else S.insert tunnel routes + +-- Parse the input file + +caveP :: Parser Cave +valveP :: Parser (RoomID, Room) +roomP :: Parser Room +tunnelsP :: Parser (S.Set Tunnel) +tunnelTextP :: Parser Text + +caveP = M.fromList <$> valveP `sepBy` endOfLine +valveP = (,) <$> ("Valve " *> (many1 letter)) <*> roomP +roomP = Room <$> (" has flow rate=" *> decimal) <*> (tunnelTextP *> tunnelsP) + -- where roomify v ts = Room {flowRate = v, tunnels = ts } +tunnelsP = (S.fromList . (fmap (flip Tunnel 1))) <$> (many1 letter) `sepBy` ", " +tunnelTextP = "; tunnels lead to valves " <|> "; tunnel leads to valve " + +successfulParse :: Text -> Cave +successfulParse input = + case parseOnly caveP input of + Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right cave -> cave \ No newline at end of file diff --git a/advent16/a16-solution.dot.png b/advent16/a16-solution.dot.png new file mode 100644 index 0000000000000000000000000000000000000000..a27adfadc48a993334f73d0c3d1bb409fa33f812 GIT binary patch literal 202269 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 Date: Sat, 22 Jul 2023 10:49:55 +0100 Subject: [PATCH 15/16] Updated blog link in comments --- advent16/Main.hs | 1 + advent16/MainSPar.hs | 1 + advent16/MainSubsets.hs | 1 + 3 files changed, 3 insertions(+) diff --git a/advent16/Main.hs b/advent16/Main.hs index 30d0843..d0540b4 100644 --- a/advent16/Main.hs +++ b/advent16/Main.hs @@ -1,4 +1,5 @@ -- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ +-- Follow up at https://work.njae.me.uk/2023/07/21/optimising-haskell-example-3/ import Debug.Trace diff --git a/advent16/MainSPar.hs b/advent16/MainSPar.hs index d3be5ec..5b68b29 100644 --- a/advent16/MainSPar.hs +++ b/advent16/MainSPar.hs @@ -1,4 +1,5 @@ -- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ +-- Follow up at https://work.njae.me.uk/2023/07/21/optimising-haskell-example-3/ import Debug.Trace diff --git a/advent16/MainSubsets.hs b/advent16/MainSubsets.hs index b927188..47d8627 100644 --- a/advent16/MainSubsets.hs +++ b/advent16/MainSubsets.hs @@ -1,4 +1,5 @@ -- Writeup at https://work.njae.me.uk/2022/12/17/advent-of-code-2022-day-16/ +-- Follow up at https://work.njae.me.uk/2023/07/21/optimising-haskell-example-3/ import Debug.Trace -- 2.34.1 From 9d0577cc4c0de3b9904ed8e5fceea6e33f149f75 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 24 Jul 2023 15:57:34 +0100 Subject: [PATCH 16/16] Optimised day 19 --- advent-of-code22.cabal | 31 ++++ advent19/Main.hs | 242 ++++++++++++++++++------------- advent19/MainExplicitClosed.hs | 258 +++++++++++++++++++++++++++++++++ advent19/MainOriginal.hs | 224 ++++++++++++++++++++++++++++ advent19/MainSingle.hs | 224 ++++++++++++++++++++++++++++ 5 files changed, 878 insertions(+), 101 deletions(-) create mode 100644 advent19/MainExplicitClosed.hs create mode 100644 advent19/MainOriginal.hs create mode 100644 advent19/MainSingle.hs diff --git a/advent-of-code22.cabal b/advent-of-code22.cabal index 8a1b109..2301cd2 100644 --- a/advent-of-code22.cabal +++ b/advent-of-code22.cabal @@ -278,11 +278,42 @@ executable advent18 main-is: advent18/Main.hs build-depends: text, attoparsec, containers, linear, lens +executable advent19original + import: common-extensions, build-directives + main-is: advent19/MainOriginal.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq + executable advent19 import: common-extensions, build-directives main-is: advent19/Main.hs build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq +executable advent19prof + import: common-extensions, build-directives + main-is: advent19/Main.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq + ghc-options: -O2 + -Wall + -threaded + -fprof-auto + -rtsopts "-with-rtsopts=-N -p -s -hT" + -- add -ls for generating the eventlog + +executable advent19excl + import: common-extensions, build-directives + main-is: advent19/MainExplicitClosed.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq + +executable advent19exprof + import: common-extensions, build-directives + main-is: advent19/MainExplicitClosed.hs + build-depends: text, attoparsec, containers, pqueue, mtl, lens, multiset, parallel, deepseq + ghc-options: -O2 + -Wall + -threaded + -fprof-auto + -rtsopts "-with-rtsopts=-N -p -s -hT" + executable advent20 import: common-extensions, build-directives main-is: advent20/Main.hs diff --git a/advent19/Main.hs b/advent19/Main.hs index 25f608a..55f6bbb 100644 --- a/advent19/Main.hs +++ b/advent19/Main.hs @@ -1,6 +1,7 @@ -- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-19/ +-- Optimised at https://work.njae.me.uk/2023/07/24/optimising-haskell-example-4/ --- import Debug.Trace +import Debug.Trace import AoC import Data.Text (Text) @@ -12,7 +13,7 @@ import qualified Data.Set as S import qualified Data.Sequence as Q import qualified Data.Map.Strict as M import Data.Map.Strict ((!)) -import Data.MultiSet as MS +import qualified Data.MultiSet as MS import Data.Sequence ((|>)) import Data.List import Data.Maybe @@ -23,17 +24,19 @@ import GHC.Generics (Generic) import Control.Parallel.Strategies import Control.DeepSeq --- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty --- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) --- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) data Resource = Ore | Clay | Obsidian | Geode - deriving (Show, Eq, Ord, Generic) + deriving (Show, Eq, Ord, Generic, Enum, Bounded) instance NFData Resource type Collection = MS.MultiSet Resource +hashCollection :: Collection -> Int +hashCollection c = + let k = 200 + in sum $ zipWith (\r n -> (MS.occur r c) * n) [minBound .. maxBound] $ iterate (* k) 1 + type Blueprint = M.Map Resource Collection data TimedBlueprint = TimedBlueprint { getBlueprint :: Blueprint, getTimeLimit :: Int, getMaxRobots :: Collection} @@ -41,63 +44,31 @@ data TimedBlueprint = TimedBlueprint { getBlueprint :: Blueprint, getTimeLimit : type BlueprintContext = Reader TimedBlueprint -data SingleSearchState = SingleSearchState +data SearchState = SearchState { _resources :: Collection , _robots :: Collection + , _currentTime :: Int } deriving (Eq, Show, Ord) -makeLenses ''SingleSearchState +makeLenses ''SearchState + +type StateHash = (Int, Int, Int) +hashSearchState :: SearchState -> StateHash +hashSearchState s = (hashCollection (s ^. resources), hashCollection (s ^. robots), s ^. currentTime) -instance NFData SingleSearchState where - rnf (SingleSearchState a b) = rnf a `seq` rnf b `seq` () +instance NFData SearchState where + rnf (SearchState a b c) = rnf a `seq` rnf b `seq` rnf c `seq` () -data Agendum s = - Agendum { _current :: s - , _trail :: Q.Seq s +data Agendum = + Agendum { _current :: SearchState + , _trail :: Q.Seq SearchState , _trailBenefit :: Int , _benefit :: Int } deriving (Show, Eq, Ord) makeLenses ''Agendum -type Agenda s = P.MaxPQueue Int (Agendum s) - -type ExploredStates s = S.Set (s, Int, Int) - - -class (Eq s, Ord s, Show s) => SearchState s where - emptySearchState :: s - successors :: s -> BlueprintContext (Q.Seq s) - estimateBenefit :: s -> Int -> BlueprintContext Int - -instance SearchState SingleSearchState where - emptySearchState = SingleSearchState { _resources = MS.empty, _robots = MS.singleton Ore } - - successors state = - do blueprint <- asks getBlueprint - maxRobots <- asks getMaxRobots - let buildableRobots = M.keys $ M.filter (\required -> required `MS.isSubsetOf` (state ^. resources)) blueprint - --- if more bots than needed for making any single bot, don't make more of that bot - let usefulRobots = MS.foldOccur (\res maxNeeded rs -> - if (MS.occur res (state ^. robots)) >= maxNeeded - then Data.List.delete res rs - else rs - ) buildableRobots maxRobots - let madeRobots = [ state & robots %~ MS.insert robot - & resources %~ ( `MS.difference` (blueprint ! robot) ) - | robot <- usefulRobots - ] - let afterBuild = [state] ++ madeRobots - let afterGather = fmap (\s -> s & resources %~ (MS.union (state ^. robots))) afterBuild - return $ Q.fromList afterGather - - - estimateBenefit currentState timeElapsed = - do timeLimit <- asks getTimeLimit - let timeRemaining = timeLimit - (timeElapsed + 1) - let currentGeodes = MS.occur Geode (currentState ^. resources) - let currentRobotsGather = (MS.occur Geode (currentState ^. robots)) * timeRemaining - let newRobotsGather = (timeRemaining * (timeRemaining + 1)) `div` 2 - return $ currentGeodes + currentRobotsGather + newRobotsGather +type Agenda = P.MaxPQueue Int Agendum +type ExploredStates = S.Set StateHash main :: IO () main = @@ -107,88 +78,157 @@ main = print $ part1 blueprints print $ part2 blueprints -part1 :: [(Int, Blueprint)] -> Int +part1, part2 :: [(Int, Blueprint)] -> Int part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- results] - where results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) - | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] - robotLimits bp = M.foldl' MS.maxUnion MS.empty bp --- part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- pResults] --- where -- results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) --- -- | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] --- -- pResults = parMap rdeepseq id results --- -- pResults = (fmap runABlueprint blueprints) `using` parList rdeepseq --- pResults = (fmap runABlueprint blueprints) `using` (parList rdeepseq) --- runABlueprint (n, blueprint) = (n, _current $ fromJust $ --- runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) --- robotLimits bp = M.foldl' MS.maxUnion MS.empty bp - -part2 :: [(Int, Blueprint)] -> Int -part2 blueprints = product [MS.occur Geode (r ^. resources) | r <- pResults] - where results = [ _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 32 (robotLimits blueprint)) - | (_, blueprint) <- (take 3 blueprints) ] :: [SingleSearchState] - pResults = parMap rdeepseq id results - robotLimits bp = M.foldl' MS.maxUnion MS.empty bp - -searchSpace :: SearchState s => BlueprintContext (Maybe (Agendum s)) +-- part1 blueprints = results + -- where results = fmap (scoreBlueprint 24) blueprints + where results = parMap rdeepseq (scoreBlueprint 24) blueprints + +-- part2 :: [(Int, Blueprint)] -> Int +part2 blueprints = product [MS.occur Geode (r ^. resources) | (_, r) <- results] + -- where results = fmap (scoreBlueprint 32) $ take 3 blueprints + where results = parMap rdeepseq (scoreBlueprint 32) $ take 3 blueprints + +robotLimits :: Blueprint -> Collection +robotLimits bp = M.foldl' MS.maxUnion MS.empty bp + +scoreBlueprint :: Int -> (Int, Blueprint) -> (Int, SearchState) +scoreBlueprint t (n, bp) = ( n + , runReader searchSpace (TimedBlueprint bp t (robotLimits bp)) + ) + +searchSpace :: BlueprintContext SearchState searchSpace = do agenda <- initAgenda - -- aStar agenda S.empty - res <- aStar agenda S.empty - return (res `seq` res) + -- searchAll agenda S.empty emptySearchState + result <- aStar agenda S.empty + return $ (fromJust result) ^. current -initAgenda :: SearchState s => BlueprintContext (Agenda s) +initAgenda :: BlueprintContext Agenda initAgenda = do let startState = emptySearchState - b <- estimateBenefit startState 0 + b <- estimateBenefit startState return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} -aStar :: SearchState s => Agenda s -> ExploredStates s -> BlueprintContext (Maybe (Agendum s)) + +aStar :: Agenda -> ExploredStates -> BlueprintContext (Maybe Agendum) aStar agenda closed - -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined - -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " benefit " ++ (show $ fst $ P.findMax agenda) ++ " : elapsed " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined | P.null agenda = return Nothing | otherwise = do let (_, currentAgendum) = P.findMax agenda let reached = currentAgendum ^. current nexts <- candidates currentAgendum closed let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts - -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width - -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width - reachedGoal <- isGoal currentAgendum - let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) - if reachedGoal + let cl = hashSearchState reached + atTimeLimit <- isTimeLimit currentAgendum + if atTimeLimit then return (Just currentAgendum) else if (cl `S.member` closed) then aStar (P.deleteMax agenda) closed - -- else aStar newAgenda (S.insert cl closed) else aStar newAgenda (S.insert cl closed) -candidates :: SearchState s => Agendum s -> ExploredStates s -> BlueprintContext (Q.Seq (Agendum s)) +candidates :: Agendum -> ExploredStates -> BlueprintContext (Q.Seq Agendum) candidates agendum closed = do let candidate = agendum ^. current let previous = agendum ^. trail - let prevBenefit = agendum ^. trailBenefit succs <- successors candidate - succAgs <- mapM (makeAgendum previous prevBenefit) succs - let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + succAgs <- mapM (makeAgendum previous) succs + let nonloops = Q.filter (\s -> (hashSearchState $ s ^. current) `S.notMember` closed) succAgs return nonloops -makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> BlueprintContext (Agendum s) -makeAgendum previous prevBenefit newState = - do predicted <- estimateBenefit newState (Q.length previous) +makeAgendum :: Q.Seq SearchState -> SearchState -> BlueprintContext Agendum +makeAgendum previous newState = + do predicted <- estimateBenefit newState let newTrail = previous |> newState - -- let incurred = geodesFound newState - let incurred = 0 + let incurred = (MS.occur Geode (newState ^. resources)) return Agendum { _current = newState , _trail = newTrail , _trailBenefit = incurred , _benefit = incurred + predicted } -isGoal :: SearchState s => Agendum s -> BlueprintContext Bool -isGoal agendum = +isTimeLimit :: Agendum -> BlueprintContext Bool +isTimeLimit agendum = do timeLimit <- asks getTimeLimit - return $ Q.length (agendum ^. trail) == timeLimit + return $ (agendum ^. current . currentTime) >= timeLimit + +emptySearchState :: SearchState +emptySearchState = SearchState { _resources = MS.empty, _robots = MS.singleton Ore, _currentTime = 0 } + +successors :: SearchState -> BlueprintContext (Q.Seq SearchState) +successors state = + do blueprint <- asks getBlueprint + maxRobots <- asks getMaxRobots + timeLimit <- asks getTimeLimit + + let robotSuccessors = Q.fromList $ catMaybes $ M.elems $ M.mapWithKey (handleRobot state maxRobots timeLimit) blueprint + + let timeRemaining = timeLimit - (state ^. currentTime) + let gathered = MS.foldOccur (\res n acc -> MS.insertMany res (n * timeRemaining) acc) + MS.empty + (state ^. robots) + let delayUntilEnd = (state & currentTime .~ timeLimit + & resources %~ (MS.union gathered) + ) + return ( robotSuccessors |> delayUntilEnd ) + +handleRobot :: SearchState -> Collection -> Int -> Resource -> Collection -> Maybe SearchState +handleRobot state maxRobots timeLimit robot recipe + | sufficientRobots robot state maxRobots = Nothing + | otherwise = buildWhenReady robot state recipe timeLimit + +-- do I already have enough of this robot? +sufficientRobots :: Resource -> SearchState -> Collection -> Bool +sufficientRobots robot state maxRobots = + (robot `MS.member` maxRobots) + && + ((MS.occur robot (state ^. robots)) >= (MS.occur robot maxRobots)) + +-- assuming I can't build this robot, how long do I have to wait for the current +-- robots to gather enough to build it? +buildDelay :: SearchState -> Collection -> Maybe Int +buildDelay state recipe + -- | MS.null delay = Just 0 + | all (\r -> MS.member r rbts) (MS.distinctElems shortfall) = Just $ maximum0 $ fmap snd $ MS.toOccurList delay + | otherwise = Nothing + where shortfall = recipe `MS.difference` (state ^. resources) + delay = MS.foldOccur calcOneDelay MS.empty shortfall + rbts = state ^. robots + calcOneDelay resource count acc = + MS.insertMany resource + -- (count `div` (MS.occur resource rbts) + 1) + (ceiling $ (fromIntegral count) / (fromIntegral $ MS.occur resource rbts)) + acc + maximum0 xs = if (null xs) then 0 else maximum xs + +buildWhenReady :: Resource -> SearchState -> Collection -> Int -> Maybe SearchState +buildWhenReady robot state recipe timeLimit = + do waitDelay <- buildDelay state recipe + delay <- tooLate (state ^. currentTime) (waitDelay + 1) timeLimit + let gathered = MS.foldOccur (\res n acc -> MS.insertMany res (n * delay) acc) + MS.empty + (state ^. robots) + return (state & robots %~ MS.insert robot -- add the robot + & resources %~ (MS.union gathered) -- add the gathered resources + & resources %~ ( `MS.difference` recipe ) -- remove the resources to build it + & currentTime %~ (+ delay) + ) + +tooLate :: Int -> Int -> Int -> Maybe Int +tooLate current delay timeLimit + | (current + delay) <= timeLimit = Just delay + | otherwise = Nothing + + +estimateBenefit :: SearchState -> BlueprintContext Int +estimateBenefit currentState = + do timeLimit <- asks getTimeLimit + let timeElapsed = currentState ^. currentTime + let timeRemaining = timeLimit - timeElapsed + let currentRobotsGather = (MS.occur Geode (currentState ^. robots)) * timeRemaining + let newRobotsGather = (timeRemaining * (timeRemaining + 1)) `div` 2 + return $ currentRobotsGather + newRobotsGather + -- Parse the input file @@ -219,4 +259,4 @@ successfulParse :: Text -> [(Int, Blueprint)] successfulParse input = case parseOnly blueprintsP input of Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err - Right blueprints -> blueprints \ No newline at end of file + Right blueprints -> blueprints diff --git a/advent19/MainExplicitClosed.hs b/advent19/MainExplicitClosed.hs new file mode 100644 index 0000000..9c5e3b8 --- /dev/null +++ b/advent19/MainExplicitClosed.hs @@ -0,0 +1,258 @@ +-- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-19/ +-- Optimised at https://work.njae.me.uk/2023/07/24/optimising-haskell-example-4/ + +import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import qualified Data.MultiSet as MS +import Data.Sequence ((|>)) +import Data.List +import Data.Maybe +-- import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import GHC.Generics (Generic) +import Control.Parallel.Strategies +import Control.DeepSeq + +data Resource = Ore | Clay | Obsidian | Geode + deriving (Show, Eq, Ord, Generic) + +instance NFData Resource + +type Collection = MS.MultiSet Resource + + +type Blueprint = M.Map Resource Collection + +data TimedBlueprint = TimedBlueprint { getBlueprint :: Blueprint, getTimeLimit :: Int, getMaxRobots :: Collection} + deriving (Show, Eq, Ord) + +type BlueprintContext = Reader TimedBlueprint + +data SearchState = SearchState + { _resources :: Collection + , _robots :: Collection + , _currentTime :: Int + } deriving (Eq, Show, Ord) +makeLenses ''SearchState + + +instance NFData SearchState where + rnf (SearchState a b c) = rnf a `seq` rnf b `seq` rnf c `seq` () + +data Agendum = + Agendum { _current :: SearchState + , _trail :: Q.Seq SearchState + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda = P.MaxPQueue Int Agendum + +type ExploredStates = S.Set SearchState + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let blueprints = successfulParse text + print $ part1 blueprints + print $ part2 blueprints + +part1, part2 :: [(Int, Blueprint)] -> Int +part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- results] +-- part1 blueprints = results + -- where results = fmap (scoreBlueprint 24) blueprints + where results = parMap rdeepseq (scoreBlueprint 24) blueprints + +-- part2 :: [(Int, Blueprint)] -> Int +part2 blueprints = product [MS.occur Geode (r ^. resources) | (_, r) <- results] + where results = parMap rdeepseq (scoreBlueprint 32) $ take 3 blueprints + +robotLimits :: Blueprint -> Collection +robotLimits bp = M.foldl' MS.maxUnion MS.empty bp + +scoreBlueprint :: Int -> (Int, Blueprint) -> (Int, SearchState) +scoreBlueprint t (n, bp) = ( n + , runReader searchSpace (TimedBlueprint bp t (robotLimits bp)) + ) + +searchSpace :: BlueprintContext SearchState +searchSpace = + do agenda <- initAgenda + -- searchAll agenda S.empty emptySearchState + result <- aStar agenda S.empty + return $ (fromJust result) ^. current + +initAgenda :: BlueprintContext Agenda +initAgenda = + do let startState = emptySearchState + b <- estimateBenefit startState + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: Agenda -> ExploredStates -> BlueprintContext (Maybe Agendum) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " benefit " ++ (show $ fst $ P.findMax agenda) ++ " : elapsed " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let cl = hashSearchState reached + atTimeLimit <- isTimeLimit currentAgendum + if atTimeLimit + then return (Just currentAgendum) + else if (reached `S.member` closed) + then aStar (P.deleteMax agenda) closed + -- else aStar newAgenda (S.insert cl closed) + else aStar newAgenda (S.insert reached closed) + +candidates :: Agendum -> ExploredStates -> BlueprintContext (Q.Seq Agendum) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + -- let nextLen = Q.length previous + 1 + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current) `S.notMember` closed) succAgs + return nonloops + +makeAgendum :: Q.Seq SearchState -> Int -> SearchState -> BlueprintContext Agendum +makeAgendum previous prevBenefit newState = + -- do predicted <- estimateBenefit newState (Q.length previous) + do predicted <- estimateBenefit newState + let newTrail = previous |> newState + let incurred = (MS.occur Geode (newState ^. resources)) + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +isTimeLimit :: Agendum -> BlueprintContext Bool +isTimeLimit agendum = + do timeLimit <- asks getTimeLimit + -- return $ Q.length (agendum ^. trail) == timeLimit + return $ (agendum ^. current . currentTime) >= timeLimit + +emptySearchState :: SearchState +emptySearchState = SearchState { _resources = MS.empty, _robots = MS.singleton Ore, _currentTime = 0 } + +successors :: SearchState -> BlueprintContext (Q.Seq SearchState) +successors state = + do blueprint <- asks getBlueprint + maxRobots <- asks getMaxRobots + timeLimit <- asks getTimeLimit + + let robotSuccessors = Q.fromList $ catMaybes $ M.elems $ M.mapWithKey (handleRobot state maxRobots timeLimit) blueprint + + let timeRemaining = timeLimit - (state ^. currentTime) + let gathered = MS.foldOccur (\res n acc -> MS.insertMany res (n * timeRemaining) acc) + MS.empty + (state ^. robots) + let delayUntilEnd = (state & currentTime .~ timeLimit + & resources %~ (MS.union gathered) + ) + return ( robotSuccessors |> delayUntilEnd ) + +handleRobot :: SearchState -> Collection -> Int -> Resource -> Collection -> Maybe SearchState +handleRobot state maxRobots timeLimit robot recipe + | sufficientRobots robot state maxRobots = Nothing + -- | buildableRobot state recipe = buildRobotAndGather robot state recipe + | otherwise = buildWhenReady robot state recipe timeLimit + +-- do I already have enough of this robot? +sufficientRobots :: Resource -> SearchState -> Collection -> Bool +sufficientRobots robot state maxRobots = + (robot `MS.member` maxRobots) + && + ((MS.occur robot (state ^. robots)) >= (MS.occur robot maxRobots)) + +buildDelay :: SearchState -> Collection -> Maybe Int +buildDelay state recipe + -- | MS.null delay = Just 0 + | all (\r -> MS.member r rbts) (MS.distinctElems shortfall) = Just $ maximum0 $ fmap snd $ MS.toOccurList delay + | otherwise = Nothing + where shortfall = recipe `MS.difference` (state ^. resources) + delay = MS.foldOccur calcOneDelay MS.empty shortfall + rbts = state ^. robots + calcOneDelay resource count acc = + MS.insertMany resource + -- (count `div` (MS.occur resource rbts) + 1) + (ceiling $ (fromIntegral count) / (fromIntegral $ MS.occur resource rbts)) + acc + maximum0 xs = if (null xs) then 0 else maximum xs + +buildWhenReady :: Resource -> SearchState -> Collection -> Int -> Maybe SearchState +buildWhenReady robot state recipe timeLimit = + do waitDelay <- buildDelay state recipe + delay <- tooLate (state ^. currentTime) (waitDelay + 1) timeLimit + let gathered = MS.foldOccur (\res n acc -> MS.insertMany res (n * delay) acc) + MS.empty + (state ^. robots) + return (state & robots %~ MS.insert robot -- add the robot + & resources %~ (MS.union gathered) + & resources %~ ( `MS.difference` recipe ) -- remove the resources to build it + & currentTime %~ (+ delay) + ) + +tooLate :: Int -> Int -> Int -> Maybe Int +tooLate current delay timeLimit + | (current + delay) <= timeLimit = Just delay + | otherwise = Nothing + + +estimateBenefit :: SearchState -> BlueprintContext Int +estimateBenefit currentState = + do timeLimit <- asks getTimeLimit + let timeElapsed = currentState ^. currentTime + let timeRemaining = timeLimit - timeElapsed + let currentRobotsGather = (MS.occur Geode (currentState ^. robots)) * timeRemaining + let newRobotsGather = (timeRemaining * (timeRemaining + 1)) `div` 2 + return $ currentRobotsGather + newRobotsGather + + +-- Parse the input file + +blueprintsP :: Parser [(Int, Blueprint)] +blueprintP :: Parser (Int, Blueprint) +robotP :: Parser (Resource, Collection) +requirementsP :: Parser Collection +requirementP :: Parser (Resource, Int) +resourceP, oreP, clayP, obsidianP, geodeP :: Parser Resource + +blueprintsP = blueprintP `sepBy` endOfLine +blueprintP = blueprintify <$> (("Blueprint " *> decimal) <* ": ") <*> (robotP `sepBy` ". ") <* "." + where blueprintify n robots = + (n, M.fromList robots) +robotP = (,) <$> ("Each " *> resourceP) <*> (" robot costs " *> requirementsP) + +requirementsP = MS.fromOccurList <$> (requirementP `sepBy` " and ") + +requirementP = (flip (,)) <$> (decimal <* " ") <*> resourceP + +resourceP = oreP <|> clayP <|> obsidianP <|> geodeP +oreP = Ore <$ "ore" +clayP = Clay <$ "clay" +obsidianP = Obsidian <$ "obsidian" +geodeP = Geode <$ "geode" + +successfulParse :: Text -> [(Int, Blueprint)] +successfulParse input = + case parseOnly blueprintsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right blueprints -> blueprints \ No newline at end of file diff --git a/advent19/MainOriginal.hs b/advent19/MainOriginal.hs new file mode 100644 index 0000000..4252c7a --- /dev/null +++ b/advent19/MainOriginal.hs @@ -0,0 +1,224 @@ +-- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-19/ + +-- import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import Data.MultiSet as MS +import Data.Sequence ((|>)) +import Data.List +import Data.Maybe +-- import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import GHC.Generics (Generic) +import Control.Parallel.Strategies +import Control.DeepSeq + +-- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty +-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) +-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) + +data Resource = Ore | Clay | Obsidian | Geode + deriving (Show, Eq, Ord, Generic) + +instance NFData Resource + +type Collection = MS.MultiSet Resource + +type Blueprint = M.Map Resource Collection + +data TimedBlueprint = TimedBlueprint { getBlueprint :: Blueprint, getTimeLimit :: Int, getMaxRobots :: Collection} + deriving (Show, Eq, Ord) + +type BlueprintContext = Reader TimedBlueprint + +data SingleSearchState = SingleSearchState + { _resources :: Collection + , _robots :: Collection + } deriving (Eq, Show, Ord) +makeLenses ''SingleSearchState + +instance NFData SingleSearchState where + rnf (SingleSearchState a b) = rnf a `seq` rnf b `seq` () + +data Agendum s = + Agendum { _current :: s + , _trail :: Q.Seq s + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda s = P.MaxPQueue Int (Agendum s) + +type ExploredStates s = S.Set (s, Int, Int) + + +class (Eq s, Ord s, Show s) => SearchState s where + emptySearchState :: s + successors :: s -> BlueprintContext (Q.Seq s) + estimateBenefit :: s -> Int -> BlueprintContext Int + +instance SearchState SingleSearchState where + emptySearchState = SingleSearchState { _resources = MS.empty, _robots = MS.singleton Ore } + + successors state = + do blueprint <- asks getBlueprint + maxRobots <- asks getMaxRobots + let buildableRobots = M.keys $ M.filter (\required -> required `MS.isSubsetOf` (state ^. resources)) blueprint + --- if more bots than needed for making any single bot, don't make more of that bot + let usefulRobots = MS.foldOccur (\res maxNeeded rs -> + if (MS.occur res (state ^. robots)) >= maxNeeded + then Data.List.delete res rs + else rs + ) buildableRobots maxRobots + let madeRobots = [ state & robots %~ MS.insert robot + & resources %~ ( `MS.difference` (blueprint ! robot) ) + | robot <- usefulRobots + ] + let afterBuild = [state] ++ madeRobots + let afterGather = fmap (\s -> s & resources %~ (MS.union (state ^. robots))) afterBuild + return $ Q.fromList afterGather + + + estimateBenefit currentState timeElapsed = + do timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 1) + let currentGeodes = MS.occur Geode (currentState ^. resources) + let currentRobotsGather = (MS.occur Geode (currentState ^. robots)) * timeRemaining + let newRobotsGather = (timeRemaining * (timeRemaining + 1)) `div` 2 + return $ currentGeodes + currentRobotsGather + newRobotsGather + + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let blueprints = successfulParse text + print $ part1 blueprints + -- print $ part2 blueprints + +-- part1 :: [(Int, Blueprint)] -> Int +part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- results] +-- part1 blueprints = pResults + where results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) + | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] + pResults = parMap rdeepseq id results + robotLimits bp = M.foldl' MS.maxUnion MS.empty bp +-- part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- pResults] +-- where -- results = [ (n, _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) +-- -- | (n, blueprint) <- blueprints ] :: [(Int, SingleSearchState)] +-- -- pResults = parMap rdeepseq id results +-- -- pResults = (fmap runABlueprint blueprints) `using` parList rdeepseq +-- pResults = (fmap runABlueprint blueprints) `using` (parList rdeepseq) +-- runABlueprint (n, blueprint) = (n, _current $ fromJust $ +-- runReader searchSpace (TimedBlueprint blueprint 24 (robotLimits blueprint)) ) +-- robotLimits bp = M.foldl' MS.maxUnion MS.empty bp + +part2 :: [(Int, Blueprint)] -> Int +part2 blueprints = product [MS.occur Geode (r ^. resources) | r <- pResults] + where results = [ _current $ fromJust $ runReader searchSpace (TimedBlueprint blueprint 32 (robotLimits blueprint)) + | (_, blueprint) <- (take 3 blueprints) ] :: [SingleSearchState] + pResults = parMap rdeepseq id results + robotLimits bp = M.foldl' MS.maxUnion MS.empty bp + +searchSpace :: SearchState s => BlueprintContext (Maybe (Agendum s)) +searchSpace = + do agenda <- initAgenda + -- aStar agenda S.empty + res <- aStar agenda S.empty + return (res `seq` res) + +initAgenda :: SearchState s => BlueprintContext (Agenda s) +initAgenda = + do let startState = emptySearchState + b <- estimateBenefit startState 0 + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: SearchState s => Agenda s -> ExploredStates s -> BlueprintContext (Maybe (Agendum s)) +aStar agenda closed + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " benefit " ++ (show $ fst $ P.findMax agenda) ++ " : elapsed " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + nexts <- candidates currentAgendum closed + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed + -- else aStar newAgenda (S.insert cl closed) + else aStar newAgenda (S.insert cl closed) + +candidates :: SearchState s => Agendum s -> ExploredStates s -> BlueprintContext (Q.Seq (Agendum s)) +candidates agendum closed = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let nonloops = Q.filter (\s -> (s ^. current, s ^. trailBenefit, Q.length $ s ^. trail) `S.notMember` closed) succAgs + return nonloops + +makeAgendum :: SearchState s => Q.Seq s -> Int -> s -> BlueprintContext (Agendum s) +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState (Q.length previous) + let newTrail = previous |> newState + -- let incurred = geodesFound newState + let incurred = 0 + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +isGoal :: SearchState s => Agendum s -> BlueprintContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + return $ Q.length (agendum ^. trail) == timeLimit + +-- Parse the input file + +blueprintsP :: Parser [(Int, Blueprint)] +blueprintP :: Parser (Int, Blueprint) +robotP :: Parser (Resource, Collection) +requirementsP :: Parser Collection +requirementP :: Parser (Resource, Int) +resourceP, oreP, clayP, obsidianP, geodeP :: Parser Resource + +blueprintsP = blueprintP `sepBy` endOfLine +blueprintP = blueprintify <$> (("Blueprint " *> decimal) <* ": ") <*> (robotP `sepBy` ". ") <* "." + where blueprintify n robots = + (n, M.fromList robots) +robotP = (,) <$> ("Each " *> resourceP) <*> (" robot costs " *> requirementsP) + +requirementsP = MS.fromOccurList <$> (requirementP `sepBy` " and ") + +requirementP = (flip (,)) <$> (decimal <* " ") <*> resourceP + +resourceP = oreP <|> clayP <|> obsidianP <|> geodeP +oreP = Ore <$ "ore" +clayP = Clay <$ "clay" +obsidianP = Obsidian <$ "obsidian" +geodeP = Geode <$ "geode" + +successfulParse :: Text -> [(Int, Blueprint)] +successfulParse input = + case parseOnly blueprintsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right blueprints -> blueprints \ No newline at end of file diff --git a/advent19/MainSingle.hs b/advent19/MainSingle.hs new file mode 100644 index 0000000..46fd58c --- /dev/null +++ b/advent19/MainSingle.hs @@ -0,0 +1,224 @@ +-- Writeup at https://work.njae.me.uk/2022/12/21/advent-of-code-2022-day-19/ + +import Debug.Trace + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Control.Applicative +import qualified Data.PQueue.Prio.Max as P +import qualified Data.Set as S +import qualified Data.Sequence as Q +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import Data.MultiSet as MS +import Data.Sequence ((|>)) +import Data.List +import Data.Maybe +-- import Data.Ord +import Control.Monad.Reader +import Control.Lens hiding ((<|), (|>), (:>), (:<), indices) +import GHC.Generics (Generic) +import Control.Parallel.Strategies +import Control.DeepSeq + +-- pattern Empty <- (Q.viewl -> Q.EmptyL) where Empty = Q.empty +-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<) = (Q.<|) +-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>) = (Q.|>) + +data Resource = Ore | Clay | Obsidian | Geode + deriving (Show, Eq, Ord, Generic) + +instance NFData Resource + +type Collection = MS.MultiSet Resource +hashCollection c = (MS.occur Ore c) + 200 * (MS.occur Clay c) + 200 * 200 * (MS.occur Obsidian c) + 200 * 200 * 200 * (MS.occur Geode c) + + +type Blueprint = M.Map Resource Collection + +data TimedBlueprint = TimedBlueprint { getBlueprint :: Blueprint, getTimeLimit :: Int, getMaxRobots :: Collection} + deriving (Show, Eq, Ord) + +type BlueprintContext = Reader TimedBlueprint + +data SearchState = SearchState + { _resources :: Collection + , _robots :: Collection + } deriving (Eq, Show, Ord) +makeLenses ''SearchState +hashSearchState s = (hashCollection (s ^. resources), hashCollection (s ^. robots)) + +instance NFData SearchState where + rnf (SearchState a b) = rnf a `seq` rnf b `seq` () + +data Agendum = + Agendum { _current :: SearchState + , _trail :: Q.Seq SearchState + , _trailBenefit :: Int + , _benefit :: Int + } deriving (Show, Eq, Ord) +makeLenses ''Agendum + +type Agenda = P.MaxPQueue Int Agendum + +-- type ExploredStates = S.Set (SearchState, Int, Int) +-- type ExploredStates = S.Set ((Int, Int), Int, Int) +type ExploredStates = S.Set ((Int, Int), Int) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let blueprints = successfulParse text + print $ part1 blueprints + -- print $ part2 blueprints + +part1 :: [(Int, Blueprint)] -> Int +part1 blueprints = sum [n * (MS.occur Geode (r ^. resources)) | (n, r) <- results] + -- where results = fmap (scoreBlueprint 24) blueprints + where results = parMap rdeepseq (scoreBlueprint 24) blueprints + +part2 :: [(Int, Blueprint)] -> Int +part2 blueprints = product [MS.occur Geode (r ^. resources) | (_, r) <- results] + where results = parMap rdeepseq (scoreBlueprint 32) $ take 3 blueprints + +robotLimits :: Blueprint -> Collection +robotLimits bp = M.foldl' MS.maxUnion MS.empty bp + +scoreBlueprint :: Int -> (Int, Blueprint) -> (Int, SearchState) +scoreBlueprint t (n, bp) = ( n + , _current $ fromJust $ runReader searchSpace (TimedBlueprint bp t (robotLimits bp)) + ) + +searchSpace :: BlueprintContext (Maybe Agendum) +searchSpace = + do agenda <- initAgenda + aStar agenda S.empty 0 + +initAgenda :: BlueprintContext Agenda +initAgenda = + do let startState = emptySearchState + b <- estimateBenefit startState 0 + return $ P.singleton b Agendum { _current = startState, _trail = Q.empty, _trailBenefit = 0, _benefit = b} + +aStar :: Agenda -> ExploredStates -> Int -> BlueprintContext (Maybe Agendum) +aStar agenda closed bestFound + -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined + -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMax agenda) ++ " benefit " ++ (show $ fst $ P.findMax agenda) ++ " : elapsed " ++ (show $ Q.length $ _trail $ snd $ P.findMax agenda)) False = undefined + -- | trace ((show bestFound) ++ " " ++ (show $ _trailBenefit $ snd $ P.findMax agenda) ++ ": " ++ (show $ _current $ snd $ P.findMax agenda)) False = undefined + | P.null agenda = return Nothing + | otherwise = + do let (_, currentAgendum) = P.findMax agenda + let reached = currentAgendum ^. current + let bestFound' = max bestFound (currentAgendum ^. trailBenefit) + nexts <- candidates currentAgendum closed bestFound' + let newAgenda = foldl' (\q a -> P.insert (_benefit a) a q) (P.deleteMax agenda) nexts + -- let beamAgenda = P.fromDescList $ P.take 10000 newAgenda -- agenda beam width + -- let beamAgenda = P.fromDescList $ P.take 5000 newAgenda -- agenda beam width + reachedGoal <- isGoal currentAgendum + -- let cl = (reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + -- let cl = (hashSearchState reached, currentAgendum ^. trailBenefit, Q.length $ currentAgendum ^. trail) + let cl = (hashSearchState reached, Q.length $ currentAgendum ^. trail) + if reachedGoal + then return (Just currentAgendum) + else if (cl `S.member` closed) + then aStar (P.deleteMax agenda) closed bestFound' + -- else aStar newAgenda (S.insert cl closed) + else aStar newAgenda (S.insert cl closed) bestFound' + +candidates :: Agendum -> ExploredStates -> Int -> BlueprintContext (Q.Seq Agendum) +candidates agendum closed bestFound = + do let candidate = agendum ^. current + let previous = agendum ^. trail + let nextLen = Q.length previous + 1 + let prevBenefit = agendum ^. trailBenefit + succs <- successors candidate + succAgs <- mapM (makeAgendum previous prevBenefit) succs + let succAgs' = Q.filter (\a -> a ^. benefit >= bestFound) succAgs + -- let nonloops = Q.filter (\s -> (hashSearchState $ s ^. current, s ^. trailBenefit, nextLen) `S.notMember` closed) succAgs' + let nonloops = Q.filter (\s -> (hashSearchState $ s ^. current, nextLen) `S.notMember` closed) succAgs' + return nonloops + +makeAgendum :: Q.Seq SearchState -> Int -> SearchState -> BlueprintContext Agendum +makeAgendum previous prevBenefit newState = + do predicted <- estimateBenefit newState (Q.length previous) + let newTrail = previous |> newState + let incurred = (MS.occur Geode (newState ^. resources)) + -- let incurred = 0 + return Agendum { _current = newState + , _trail = newTrail + , _trailBenefit = incurred + , _benefit = incurred + predicted + } + +isGoal :: Agendum -> BlueprintContext Bool +isGoal agendum = + do timeLimit <- asks getTimeLimit + return $ Q.length (agendum ^. trail) == timeLimit + +emptySearchState :: SearchState +emptySearchState = SearchState { _resources = MS.empty, _robots = MS.singleton Ore } + +successors :: SearchState -> BlueprintContext (Q.Seq SearchState) +successors state = + do blueprint <- asks getBlueprint + maxRobots <- asks getMaxRobots + let buildableRobots = M.keys $ M.filter (\required -> required `MS.isSubsetOf` (state ^. resources)) blueprint + --- if more bots than needed for making any single bot, don't make more of that bot + let usefulRobots = MS.foldOccur (\res maxNeeded rs -> + if (MS.occur res (state ^. robots)) >= maxNeeded + then Data.List.delete res rs + else rs + ) buildableRobots maxRobots + let madeRobots = [ state & robots %~ MS.insert robot + & resources %~ ( `MS.difference` (blueprint ! robot) ) + | robot <- usefulRobots + ] + let afterBuild = [state] ++ madeRobots + let afterGather = fmap (\s -> s & resources %~ (MS.union (state ^. robots))) afterBuild + return $ Q.fromList afterGather + + +estimateBenefit :: SearchState -> Int -> BlueprintContext Int +estimateBenefit currentState timeElapsed = + do timeLimit <- asks getTimeLimit + let timeRemaining = timeLimit - (timeElapsed + 1) + -- let currentGeodes = MS.occur Geode (currentState ^. resources) + let currentRobotsGather = (MS.occur Geode (currentState ^. robots)) * timeRemaining + let newRobotsGather = (timeRemaining * (timeRemaining + 1)) `div` 2 + -- return $ currentGeodes + currentRobotsGather + newRobotsGather + return $ currentRobotsGather + newRobotsGather + + +-- Parse the input file + +blueprintsP :: Parser [(Int, Blueprint)] +blueprintP :: Parser (Int, Blueprint) +robotP :: Parser (Resource, Collection) +requirementsP :: Parser Collection +requirementP :: Parser (Resource, Int) +resourceP, oreP, clayP, obsidianP, geodeP :: Parser Resource + +blueprintsP = blueprintP `sepBy` endOfLine +blueprintP = blueprintify <$> (("Blueprint " *> decimal) <* ": ") <*> (robotP `sepBy` ". ") <* "." + where blueprintify n robots = + (n, M.fromList robots) +robotP = (,) <$> ("Each " *> resourceP) <*> (" robot costs " *> requirementsP) + +requirementsP = MS.fromOccurList <$> (requirementP `sepBy` " and ") + +requirementP = (flip (,)) <$> (decimal <* " ") <*> resourceP + +resourceP = oreP <|> clayP <|> obsidianP <|> geodeP +oreP = Ore <$ "ore" +clayP = Clay <$ "clay" +obsidianP = Obsidian <$ "obsidian" +geodeP = Geode <$ "geode" + +successfulParse :: Text -> [(Int, Blueprint)] +successfulParse input = + case parseOnly blueprintsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right blueprints -> blueprints \ No newline at end of file -- 2.34.1