Heuristic Search Algorithms
Heuristic Search Algorithms
Instructor:Faheem Mahmood
March 16, 2024
import simpleai as sa
print(sa)
Collecting simpleai
Downloading simpleai-0.8.3.tar.gz (94 kB)
Building wheels for collected packages: simpleai
Building wheel for simpleai (setup.py): started
Building wheel for simpleai (setup.py): finished with status 'done'
Created wheel for simpleai: filename=simpleai-0.8.3-py3-none-any.whl
size=101000
sha256=a5eafe893302e4e0eded26358acd6dcb29fbd74dc239abfd0d6885d8fc52a72e
Stored in directory: c:\users\ahmad\appdata\local\pip\cache\wheels\49\98\03\7b
d5011c19ca8909a0db02f6c8a536d339ac356a17cac01372
Successfully built simpleai
Installing collected packages: simpleai
1
Successfully installed simpleai-0.8.3
Note: you may need to restart the kernel to use updated packages.
Simple AI allows you to define problems and look for the solution with different strategies. Here
is an easiest problem which is familiar to you This problem tries to create the string “HELLO
WORLD” using the A* algorithm:
class HelloProblem(SearchProblem):
def actions(self, state):
if len(state) < len(GOAL):
return list(' ABCDEFGHIJKLMNOPQRSTUVWXYZ')
else:
return []
problem = HelloProblem(initial_state='')
result = astar(problem)
print(result.state)
print(result.path())
HELLO WORLD
[(None, ''), ('H', 'H'), ('E', 'HE'), ('L', 'HEL'), ('L', 'HELL'), ('O',
'HELLO'), (' ', 'HELLO '), ('W', 'HELLO W'), ('O', 'HELLO WO'), ('R', 'HELLO
WOR'), ('L', 'HELLO WORL'), ('D', 'HELLO WORLD')]
2
The Algorithm: Pick any node, visit the adjacent unvisited vertex, mark it as visited, display it,
and insert it in a queue. If there are no remaining adjacent vertices left, remove the first vertex
from the queue. Repeat step 1 and step 2 until the queue is empty or the desired node is found.
Implementation Consider the graph, which is implemented in the code below:
3
[4]: graph = {
'A' : ['B','C'],
'B' : ['D', 'E'],
'C' : ['F'],
'D' : [],
'E' : ['F'],
'F' : []
}
while queue:
s = queue.pop(0)
print (s, end = " ")
# Driver Code
bfs(visited, graph, 'A')
A B C D E F
1.2.1 Explanation
Lines 3-10: The illustrated graph is represented using an adjacency list. An easy way to do this
in Python is to use a dictionary data structure, where each vertex has a stored list of its adjacent
nodes.
Line 12: visited is a list that is used to keep track of visited nodes.
Line 13: queue is a list that is used to keep track of nodes currently in the queue.
Line 29: The arguments of the bfs function are the visited list, the graph in the form of a dictionary,
and the starting node A.
Lines 15-26: bfs follows the algorithm described above:
It checks and appends the starting node to the visited list and the queue. Then, while the queue
contains elements, it keeps taking out nodes from the queue, appends the neighbors of that node
to the queue if they are unvisited, and marks them as visited. This continues until the queue is
empty.
4
1.3 Depth-first search (DFS)
Depth-first search (DFS), is an algorithm for tree traversal on graph or tree data structures. It can
be implemented easily using recursion and data structures like dictionaries and sets.
The Algorithm: Pick any node. If it is unvisited, mark it as visited and recur on all its adjacent
nodes. Repeat until all the nodes are visited, or the node to be searched is found.
Implementation Consider this graph, implemented in the code below:
5
[5]: # Using a Python dictionary to act as an adjacency list
graph = {
'A' : ['B','C'],
'B' : ['D', 'E'],
'C' : ['F'],
'D' : [],
'E' : ['F'],
'F' : []
}
# Driver Code
dfs(visited, graph, 'A')
A
B
D
E
F
C
1.3.1 Explanation
Lines 2-9: The illustrated graph is represented using an adjacency list - an easy way to do it in
Python is to use a dictionary data structure. Each vertex has a list of its adjacent nodes stored.
Line 11: visited is a set that is used to keep track of visited nodes. Line 21: The dfs function
is called and is passed the visited set, the graph in the form of a dictionary, and A, which is the
starting node. Lines 13-18: dfs follows the algorithm described above: It first checks if the current
node is unvisited - if yes, it is appended in the visited set. Then for each neighbor of the current
node, the dfs function is invoked again. The base case is invoked when all the nodes are visited.
The function then returns.
6
[6]: from simpleai.search import CspProblem, backtrack
if __name__ == '__main__':
# Specify the variables
names = ('Mark', 'Julia', 'Steve', 'Amanda', 'Brian', 'Joanne', 'Derek',␣
,→'Allan', 'Michelle', 'Kelly')
7
(('Julia', 'Derek'), constraint_func),
(('Julia', 'Brian'), constraint_func),
(('Steve', 'Amanda'), constraint_func),
(('Steve', 'Allan'), constraint_func),
(('Steve', 'Michelle'), constraint_func),
(('Amanda', 'Michelle'), constraint_func),
(('Amanda', 'Joanne'), constraint_func),
(('Amanda', 'Derek'), constraint_func),
(('Brian', 'Derek'), constraint_func),
(('Brian', 'Kelly'), constraint_func),
(('Joanne', 'Michelle'), constraint_func),
(('Joanne', 'Amanda'), constraint_func),
(('Joanne', 'Derek'), constraint_func),
(('Joanne', 'Kelly'), constraint_func),
(('Derek', 'Kelly'), constraint_func),
]
Color mapping: