Skip to content

Commit ba35aa4

Browse files
goswami-rahulnorvig
authored andcommitted
refactored FIFOQueue, Stack, and PriorityQueue (#878)
1 parent 3e790e9 commit ba35aa4

File tree

7 files changed

+215
-274
lines changed

7 files changed

+215
-274
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
7272
| 3.2 | Romania | `romania` | [`search.py`][search] | Done | Included |
7373
| 3.7 | Tree-Search | `tree_search` | [`search.py`][search] | Done | |
7474
| 3.7 | Graph-Search | `graph_search` | [`search.py`][search] | Done | |
75-
| 3.11 | Breadth-First-Search | `breadth_first_search` | [`search.py`][search] | Done | Included |
75+
| 3.11 | Breadth-First-Search | `breadth_first_graph_search` | [`search.py`][search] | Done | Included |
7676
| 3.14 | Uniform-Cost-Search | `uniform_cost_search` | [`search.py`][search] | Done | Included |
7777
| 3.17 | Depth-Limited-Search | `depth_limited_search` | [`search.py`][search] | Done | |
7878
| 3.18 | Iterative-Deepening-Search | `iterative_deepening_search` | [`search.py`][search] | Done | |

gui/romania_problem.py

Lines changed: 96 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
66
from search import *
77
from search import breadth_first_tree_search as bfts, depth_first_tree_search as dfts, \
8-
depth_first_graph_search as dfgs, breadth_first_search as bfs, uniform_cost_search as ucs, \
8+
depth_first_graph_search as dfgs, breadth_first_graph_search as bfs, uniform_cost_search as ucs, \
99
astar_search as asts
10-
from utils import Stack, FIFOQueue, PriorityQueue
10+
from utils import PriorityQueue
1111
from copy import deepcopy
1212

1313
root = None
@@ -26,9 +26,7 @@
2626

2727

2828
def create_map(root):
29-
'''
30-
This function draws out the required map.
31-
'''
29+
"""This function draws out the required map."""
3230
global city_map, start, goal
3331
romania_locations = romania_map.locations
3432
width = 750
@@ -260,17 +258,13 @@ def create_map(root):
260258

261259

262260
def make_line(map, x0, y0, x1, y1, distance):
263-
'''
264-
This function draws out the lines joining various points.
265-
'''
261+
"""This function draws out the lines joining various points."""
266262
map.create_line(x0, y0, x1, y1)
267263
map.create_text((x0 + x1) / 2, (y0 + y1) / 2, text=distance)
268264

269265

270266
def make_rectangle(map, x0, y0, margin, city_name):
271-
'''
272-
This function draws out rectangles for various points.
273-
'''
267+
"""This function draws out rectangles for various points."""
274268
global city_coord
275269
rect = map.create_rectangle(
276270
x0 - margin,
@@ -313,51 +307,51 @@ def make_legend(map):
313307

314308

315309
def tree_search(problem):
316-
'''
310+
"""
317311
Search through the successors of a problem to find a goal.
318312
The argument frontier should be an empty queue.
319313
Don't worry about repeated paths to a state. [Figure 3.7]
320314
This function has been changed to make it suitable for the Tkinter GUI.
321-
'''
315+
"""
322316
global counter, frontier, node
323-
# print(counter)
317+
324318
if counter == -1:
325319
frontier.append(Node(problem.initial))
326-
# print(frontier)
320+
327321
display_frontier(frontier)
328322
if counter % 3 == 0 and counter >= 0:
329323
node = frontier.pop()
330-
# print(node)
324+
331325
display_current(node)
332326
if counter % 3 == 1 and counter >= 0:
333327
if problem.goal_test(node.state):
334-
# print(node)
328+
335329
return node
336330
frontier.extend(node.expand(problem))
337-
# print(frontier)
331+
338332
display_frontier(frontier)
339333
if counter % 3 == 2 and counter >= 0:
340-
# print(node)
334+
341335
display_explored(node)
342336
return None
343337

344338

345339
def graph_search(problem):
346-
'''
340+
"""
347341
Search through the successors of a problem to find a goal.
348342
The argument frontier should be an empty queue.
349343
If two paths reach a state, only use the first one. [Figure 3.7]
350344
This function has been changed to make it suitable for the Tkinter GUI.
351-
'''
345+
"""
352346
global counter, frontier, node, explored
353347
if counter == -1:
354348
frontier.append(Node(problem.initial))
355349
explored = set()
356-
# print("Frontier: "+str(frontier))
350+
357351
display_frontier(frontier)
358352
if counter % 3 == 0 and counter >= 0:
359353
node = frontier.pop()
360-
# print("Current node: "+str(node))
354+
361355
display_current(node)
362356
if counter % 3 == 1 and counter >= 0:
363357
if problem.goal_test(node.state):
@@ -366,18 +360,15 @@ def graph_search(problem):
366360
frontier.extend(child for child in node.expand(problem)
367361
if child.state not in explored and
368362
child not in frontier)
369-
# print("Frontier: " + str(frontier))
363+
370364
display_frontier(frontier)
371365
if counter % 3 == 2 and counter >= 0:
372-
# print("Explored node: "+str(node))
373366
display_explored(node)
374367
return None
375368

376369

377370
def display_frontier(queue):
378-
'''
379-
This function marks the frontier nodes (orange) on the map.
380-
'''
371+
"""This function marks the frontier nodes (orange) on the map."""
381372
global city_map, city_coord
382373
qu = deepcopy(queue)
383374
while qu:
@@ -388,63 +379,92 @@ def display_frontier(queue):
388379

389380

390381
def display_current(node):
391-
'''
392-
This function marks the currently exploring node (red) on the map.
393-
'''
382+
"""This function marks the currently exploring node (red) on the map."""
394383
global city_map, city_coord
395384
city = node.state
396385
city_map.itemconfig(city_coord[city], fill="red")
397386

398387

399388
def display_explored(node):
400-
'''
401-
This function marks the already explored node (gray) on the map.
402-
'''
389+
"""This function marks the already explored node (gray) on the map."""
403390
global city_map, city_coord
404391
city = node.state
405392
city_map.itemconfig(city_coord[city], fill="gray")
406393

407394

408395
def display_final(cities):
409-
'''
410-
This function marks the final solution nodes (green) on the map.
411-
'''
396+
"""This function marks the final solution nodes (green) on the map."""
412397
global city_map, city_coord
413398
for city in cities:
414399
city_map.itemconfig(city_coord[city], fill="green")
415400

416401

417402
def breadth_first_tree_search(problem):
418403
"""Search the shallowest nodes in the search tree first."""
419-
global frontier, counter
404+
global frontier, counter, node
420405
if counter == -1:
421-
frontier = FIFOQueue()
422-
return tree_search(problem)
406+
frontier = deque()
407+
408+
if counter == -1:
409+
frontier.append(Node(problem.initial))
410+
411+
display_frontier(frontier)
412+
if counter % 3 == 0 and counter >= 0:
413+
node = frontier.popleft()
414+
415+
display_current(node)
416+
if counter % 3 == 1 and counter >= 0:
417+
if problem.goal_test(node.state):
418+
return node
419+
frontier.extend(node.expand(problem))
420+
421+
display_frontier(frontier)
422+
if counter % 3 == 2 and counter >= 0:
423+
display_explored(node)
424+
return None
423425

424426

425427
def depth_first_tree_search(problem):
426428
"""Search the deepest nodes in the search tree first."""
427429
# This search algorithm might not work in case of repeated paths.
428-
global frontier, counter
430+
global frontier, counter, node
429431
if counter == -1:
430-
frontier = Stack()
431-
return tree_search(problem)
432+
frontier = [] # stack
433+
434+
if counter == -1:
435+
frontier.append(Node(problem.initial))
436+
437+
display_frontier(frontier)
438+
if counter % 3 == 0 and counter >= 0:
439+
node = frontier.pop()
440+
441+
display_current(node)
442+
if counter % 3 == 1 and counter >= 0:
443+
if problem.goal_test(node.state):
444+
return node
445+
frontier.extend(node.expand(problem))
446+
447+
display_frontier(frontier)
448+
if counter % 3 == 2 and counter >= 0:
449+
display_explored(node)
450+
return None
432451

433452

434-
def breadth_first_search(problem):
453+
def breadth_first_graph_search(problem):
435454
"""[Figure 3.11]"""
436455
global frontier, node, explored, counter
437456
if counter == -1:
438457
node = Node(problem.initial)
439458
display_current(node)
440459
if problem.goal_test(node.state):
441460
return node
442-
frontier = FIFOQueue()
443-
frontier.append(node)
461+
462+
frontier = deque([node]) # FIFO queue
463+
444464
display_frontier(frontier)
445465
explored = set()
446466
if counter % 3 == 0 and counter >= 0:
447-
node = frontier.pop()
467+
node = frontier.popleft()
448468
display_current(node)
449469
explored.add(node.state)
450470
if counter % 3 == 1 and counter >= 0:
@@ -461,10 +481,30 @@ def breadth_first_search(problem):
461481

462482
def depth_first_graph_search(problem):
463483
"""Search the deepest nodes in the search tree first."""
464-
global frontier, counter
484+
global counter, frontier, node, explored
465485
if counter == -1:
466-
frontier = Stack()
467-
return graph_search(problem)
486+
frontier = [] # stack
487+
if counter == -1:
488+
frontier.append(Node(problem.initial))
489+
explored = set()
490+
491+
display_frontier(frontier)
492+
if counter % 3 == 0 and counter >= 0:
493+
node = frontier.pop()
494+
495+
display_current(node)
496+
if counter % 3 == 1 and counter >= 0:
497+
if problem.goal_test(node.state):
498+
return node
499+
explored.add(node.state)
500+
frontier.extend(child for child in node.expand(problem)
501+
if child.state not in explored and
502+
child not in frontier)
503+
504+
display_frontier(frontier)
505+
if counter % 3 == 2 and counter >= 0:
506+
display_explored(node)
507+
return None
468508

469509

470510
def best_first_graph_search(problem, f):
@@ -483,7 +523,7 @@ def best_first_graph_search(problem, f):
483523
display_current(node)
484524
if problem.goal_test(node.state):
485525
return node
486-
frontier = PriorityQueue(min, f)
526+
frontier = PriorityQueue('min', f)
487527
frontier.append(node)
488528
display_frontier(frontier)
489529
explored = set()
@@ -525,9 +565,9 @@ def astar_search(problem, h=None):
525565
# Remove redundant code.
526566
# Make the interchangbility work between various algorithms at each step.
527567
def on_click():
528-
'''
568+
"""
529569
This function defines the action of the 'Next' button.
530-
'''
570+
"""
531571
global algo, counter, next_button, romania_problem, start, goal
532572
romania_problem = GraphProblem(start.get(), goal.get(), romania_map)
533573
if "Breadth-First Tree Search" == algo.get():
@@ -546,8 +586,8 @@ def on_click():
546586
display_final(final_path)
547587
next_button.config(state="disabled")
548588
counter += 1
549-
elif "Breadth-First Search" == algo.get():
550-
node = breadth_first_search(romania_problem)
589+
elif "Breadth-First Graph Search" == algo.get():
590+
node = breadth_first_graph_search(romania_problem)
551591
if node is not None:
552592
final_path = bfs(romania_problem).solution()
553593
final_path.append(start.get())
@@ -605,7 +645,7 @@ def main():
605645
algorithm_menu = OptionMenu(
606646
root,
607647
algo, "Breadth-First Tree Search", "Depth-First Tree Search",
608-
"Breadth-First Search", "Depth-First Graph Search",
648+
"Breadth-First Graph Search", "Depth-First Graph Search",
609649
"Uniform Cost Search", "A* - Search")
610650
Label(root, text="\n Search Algorithm").pack()
611651
algorithm_menu.pack()

planning.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
import itertools
55
from search import Node
6-
from utils import Expr, expr, first, FIFOQueue
6+
from utils import Expr, expr, first
77
from logic import FolKB
8+
from collections import deque
89

910

1011
class PDDL:
@@ -727,16 +728,16 @@ def hierarchical_search(problem, hierarchy):
727728
"""
728729
[Figure 11.5] 'Hierarchical Search, a Breadth First Search implementation of Hierarchical
729730
Forward Planning Search'
730-
The problem is a real-world prodlem defined by the problem class, and the hierarchy is
731+
The problem is a real-world problem defined by the problem class, and the hierarchy is
731732
a dictionary of HLA - refinements (see refinements generator for details)
732733
"""
733734
act = Node(problem.actions[0])
734-
frontier = FIFOQueue()
735+
frontier = deque()
735736
frontier.append(act)
736-
while(True):
737+
while True:
737738
if not frontier:
738739
return None
739-
plan = frontier.pop()
740+
plan = frontier.popleft()
740741
print(plan.state.name)
741742
hla = plan.state # first_or_null(plan)
742743
prefix = None

0 commit comments

Comments
 (0)