Skip to content

Commit ba301e7

Browse files
antmarakisnorvig
authored andcommitted
Search: Bidirectional Search (aimacode#554)
* Add bidirectional search + update h function * add bidirectional search test
1 parent be8302f commit ba301e7

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

search.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,85 @@ def iterative_deepening_search(problem):
305305
if result != 'cutoff':
306306
return result
307307

308+
# ______________________________________________________________________________
309+
# Bidirectional Search
310+
# Pseudocode from https://webdocs.cs.ualberta.ca/%7Eholte/Publications/MM-AAAI2016.pdf
311+
312+
def bidirectional_search(problem):
313+
e = problem.find_min_edge()
314+
gF, gB = {problem.initial : 0}, {problem.goal : 0}
315+
openF, openB = [problem.initial], [problem.goal]
316+
closedF, closedB = [], []
317+
U = infinity
318+
319+
320+
def extend(U, open_dir, open_other, g_dir, g_other, closed_dir):
321+
"""Extend search in given direction"""
322+
n = find_key(C, open_dir, g_dir)
323+
324+
open_dir.remove(n)
325+
closed_dir.append(n)
326+
327+
for c in problem.actions(n):
328+
if c in open_dir or c in closed_dir:
329+
if g_dir[c] <= problem.path_cost(g_dir[n], n, None, c):
330+
continue
331+
332+
open_dir.remove(c)
333+
334+
g_dir[c] = problem.path_cost(g_dir[n], n, None, c)
335+
open_dir.append(c)
336+
337+
if c in open_other:
338+
U = min(U, g_dir[c] + g_other[c])
339+
340+
return U, open_dir, closed_dir, g_dir
341+
342+
343+
def find_min(open_dir, g):
344+
"""Finds minimum priority, g and f values in open_dir"""
345+
m, m_f = infinity, infinity
346+
for n in open_dir:
347+
f = g[n] + problem.h(n)
348+
pr = max(f, 2*g[n])
349+
m = min(m, pr)
350+
m_f = min(m_f, f)
351+
352+
return m, m_f, min(g.values())
353+
354+
355+
def find_key(pr_min, open_dir, g):
356+
"""Finds key in open_dir with value equal to pr_min
357+
and minimum g value."""
358+
m = infinity
359+
state = -1
360+
for n in open_dir:
361+
pr = max(g[n] + problem.h(n), 2*g[n])
362+
if pr == pr_min:
363+
if g[n] < m:
364+
m = g[n]
365+
state = n
366+
367+
return state
368+
369+
370+
while openF and openB:
371+
pr_min_f, f_min_f, g_min_f = find_min(openF, gF)
372+
pr_min_b, f_min_b, g_min_b = find_min(openB, gB)
373+
C = min(pr_min_f, pr_min_b)
374+
375+
if U <= max(C, f_min_f, f_min_b, g_min_f + g_min_b + e):
376+
return U
377+
378+
if C == pr_min_f:
379+
# Extend forward
380+
U, openF, closedF, gF = extend(U, openF, openB, gF, gB, closedF)
381+
else:
382+
# Extend backward
383+
U, openB, closedB, gB = extend(U, openB, openF, gB, gF, closedB)
384+
385+
return infinity
386+
308387
# ______________________________________________________________________________
309388
# Informed (Heuristic) Search
310389

@@ -848,6 +927,9 @@ def h(self, node):
848927
"""h function is straight-line distance from a node's state to goal."""
849928
locs = getattr(self.graph, 'locations', None)
850929
if locs:
930+
if type(node) is str:
931+
return int(distance(locs[node], locs[self.goal]))
932+
851933
return int(distance(locs[node.state], locs[self.goal]))
852934
else:
853935
return infinity

tests/test_search.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ def test_depth_limited_search():
4343
assert solution_50[-1] == 'Bucharest'
4444

4545

46+
def test_bidirectional_search():
47+
assert bidirectional_search(romania_problem) == 418
48+
49+
4650
def test_astar_search():
4751
assert astar_search(romania_problem).solution() == ['Sibiu', 'Rimnicu', 'Pitesti', 'Bucharest']
4852

0 commit comments

Comments
 (0)