-
Notifications
You must be signed in to change notification settings - Fork 0
/
Search.py
122 lines (89 loc) · 3.98 KB
/
Search.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""
Artificial Intelligence | Fall 2018
Homework - I | 08 September 2018 | Due: 07 Septmeber 2018
Narinder Singh
"""
import Tree
from Tree import Node
from Queue import Queue
from Stack import Stack
class SearchErrors(Exception): pass
class NoSolutionFoundError(SearchErrors): pass
class Solution(Exception):
""" Describes a solution of a search algorithm by tracking the progress of a search algorithm. """
def __init__(self, verbose = False):
""" Initialize the instance with runtime given characterisitics. """
self._algorithm = ''
self._maxFrontierSize = 0
self._maxExploredSetSize = 0
self._verbose = verbose
self._goalNode = None
def trackProgress(self, frontier, exploredSet = []):
""" Track the runtime performance of the """
self._maxFrontierSize = max(self.getMaxFrontierSize(), len(frontier))
self._maxExploredSetSize = max(self.getMaxExploredSetSize(), len(exploredSet))
if self._verbose:
print 'Frontier: ' + str(frontier)
print 'Explored Set: ' + str(exploredSet) + '\n'
def getMaxFrontierSize(self):
""" Return maximum size that the fronier grew up to so far. """
return self._maxFrontierSize
def getMaxExploredSetSize(self):
""" Return maximum size that the explored set grew up to so far. """
return self._maxExploredSetSize
def getGoalNode(self):
""" Return goal node as set by the search algorithm. """
return self._goalNode
def setGoalNode(self, goal):
""" Set the goal node. """
self._goalNode = goal
return self
def getGoalPath(self):
""" Construct and return a path from "root" to the given node. """
return Tree.getGoalPath(self.getGoalNode())
def getActionSequenceToGoal(self):
""" Construct and return the action sequence that takes you from "root" to the given node. """
return Tree.getActionSequenceToGoal(self.getGoalNode())
def summary(self):
""" Summarises the solution. """
goalPath = 'Goal Path: ' + ', '.join([str(x) for x in self.getGoalPath()])
actionSequence = 'Action Sequence: ' + ', '.join([str(x) for x in self.getActionSequenceToGoal()])
maxFrontier = 'Maximum Frontier size: ' + str(self.getMaxFrontierSize())
maxExplored = 'Maximum Explored Set size: ' + str(self.getMaxExploredSetSize())
return '\n'.join([goalPath, actionSequence, maxFrontier, maxExplored])
def breadthFirstSearch(problem, verbose=False):
""" Perform a Breadth-First search on the given problem and return a solution.
NOTE: This is a graph based implementation of the algorithm, please be aware of the memory overhead."""
start = Node(problem, state = problem.initialState())
solution = Solution(verbose)
if problem.goalTest(start.state()): return solution.setGoalNode(start)
frontier = Queue(items=[start])
explored = set()
while True:
solution.trackProgress(frontier, explored)
if frontier.isEmpty(): raise NoSolutionFoundError()
node = frontier.dequeue()
explored.add(node.state())
for action in problem.applicableActions(node.state()):
child = Node(problem, node, action)
if child not in frontier and child.state() not in explored:
if problem.goalTest(child.state()): return solution.setGoalNode(child)
else: frontier.enqueue(child)
def depthFirstSearch(problem, verbose=False):
""" Perform a Depth-First search on the given problem and return a solution.
NOTE: This is a graph based implementation of the algorithm, please be aware of the memory overhead."""
start = Node(problem, state = problem.initialState())
solution = Solution(verbose)
if problem.goalTest(start.state()): return solution.setGoalNode(start)
frontier = Stack(items=[start])
explored = set()
while True:
solution.trackProgress(frontier, explored)
if frontier.isEmpty(): raise NoSolutionFoundError()
node = frontier.pop()
explored.add(node.state())
for action in problem.applicableActions(node.state()):
child = Node(problem, node, action)
if child not in frontier and child.state() not in explored:
if problem.goalTest(child.state()): return solution.setGoalNode(child)
frontier.push(child)