From 910da239c046408511ba10a1f8c147b27dbf3031 Mon Sep 17 00:00:00 2001 From: Andrew Ekstedt Date: Sat, 17 Dec 2022 19:51:23 -0800 Subject: [PATCH] new A* optimization: worst-case pruning i'm not sure if this has been described in the literature exactly but it is similar to existing branch-and-bound techniques. it doesn't speed up the search directly (the number of visited nodes is the same) but it does cut the queue length down by an order of magnitude and shave a couple seconds off of day 16, presumably due to reduced memory pressure or something. --- day16/sol.py | 6 +++++- lib/astar.py | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/day16/sol.py b/day16/sol.py index a888581..2a9a9cc 100644 --- a/day16/sol.py +++ b/day16/sol.py @@ -152,6 +152,10 @@ def solve(): m -= 1 return c + def worst2(node): + _, _, min1, min2, closed = node + return min(min1,min2) * pressure(closed) + def is_goal2(node): _, _, min1, min2, closed = node return min1 == 0 and min2 == 0 or closed == all_open @@ -209,7 +213,7 @@ def solve(): minutes = 26 start2 = (AA, AA, minutes, minutes, all_closed) info.clear() - c, _, path = astar.search(start2, is_goal2, neighbors2, heuristic2) + c, _, path = astar.search(start2, is_goal2, neighbors2, heuristic2, worst=worst2) print(c) print(max_pressure*minutes - c) diff --git a/lib/astar.py b/lib/astar.py index b6eed66..e1fa793 100644 --- a/lib/astar.py +++ b/lib/astar.py @@ -1,6 +1,6 @@ from heapq import heappush, heappop -def search(start, is_goal, neighbors, heuristic=None): +def search(start, is_goal, neighbors, heuristic=None, worst=None): if heuristic == None: def heuristic(x): return 0 @@ -16,6 +16,8 @@ def search(start, is_goal, neighbors, heuristic=None): i += 1 heappush(q, (heuristic(s), i, s, None)) done = {} + if worst: + best_worst = min(worst(s) for s in start) while q: z, _, this, prev = heappop(q) if this in done: @@ -41,8 +43,15 @@ def search(start, is_goal, neighbors, heuristic=None): c = cost_so_far + c if n not in done or c < done[n][0]: h = heuristic(n) - if h is None: - continue + if worst: + if c+h > best_worst: + # if the best possible cost for this node + # is worse than the lowest worst-case cost we've seen + # then don't even bother exploring it + continue + w = worst(n) + if c+w < best_worst: + best_worst = c+w i += 1 heappush(q, (c+h, i, n, this))