Assignment No 2
Assignment No 2
Artificial Intelligence
Submitted By
Aiman Mustafa (SP21073)
Sofia Masood (SP21072)
Touseef Wali (SP21054)
Muhammad Roohan (SP21051)
Submitted To
Ms. Qurat-Ul-Ain Raja
Date
5 April 2023
Execute the python code for A* Search algorithm and provide the results.
Solution:
A* search algorithm can be used to find the most cost-effective path in a graph. Consider the
following graph below.
The numbers written on edges represent the distance between the nodes, while the numbers
written on nodes represent the heuristic values. Let us find the most cost-effective path to reach
from start state A to final state G using the A* Algorithm.
Let’s start with node A. Since A is a starting node, therefore, the value of g(x) for A is zero, and
from the graph, we get the heuristic value of A is 11, therefore
g(x) + h(x) = f(x)
0+ 11 =11
Thus for A, we can write
A=11
Now from A, we can go to point B or point E, so we compute f(x) for each of them
A→B=2+6=8
A→E=3+6=9
Since the cost for A → B is less, we move forward with this path and compute the f(x) for the
children nodes of B
Since there is no path between C and G, the heuristic cost is set to infinity or a very high value
A → B → C = (2 + 1) + 99= 102
A → B → G = (2 + 9 ) + 0 = 11
Here the path A → B → G has the least cost but it is still more than the cost of A → E, thus we
explore this path further
A → E → D = (3 + 6) + 1 = 10
Comparing the cost of A → E → D with all the paths we got so far and as this cost is least of all
we move forward with this path. And compute the f(x) for the children of D
A → E → D → G = (3 + 6 + 1) +0 =10
Now comparing all the paths that lead us to the goal, we conclude that A → E → D → G is the
most cost-effective path to get from A to G.
CODE:
def aStarAlgo(start_node, stop_node):
open_set = set(start_node)
closed_set = set()
g = {} #store distance from starting node
parents = {}# parents contains an adjacency map of all nodes
#ditance of starting node from itself is zero
g[start_node] = 0
#start_node is root node i.e it has no parent nodes
#so start_node is set to its own parent node
parents[start_node] = start_node
while len(open_set) > 0:
n = None
#node with lowest f() is found
for v in open_set:
if n == None or g[v] + heuristic(v) < g[n] + heuristic(n):
n = v
if n == stop_node or Graph_nodes[n] == None:
pass
else:
for (m, weight) in get_neighbors(n):
#nodes 'm' not in first and last set are added to firs
t
#n is set its parent
if m not in open_set and m not in closed_set:
open_set.add(m)
parents[m] = n
g[m] = g[n] + weight
#for each node m,compare its distance from start i.e g
(m) to the
#from start through n node
else:
if g[m] > g[n] + weight:
#update g(m)
g[m] = g[n] + weight
#change parent of m to n
parents[m] = n
#if m in closed set,remove and add to open
if m in closed_set:
closed_set.remove(m)
open_set.add(m)
if n == None:
print('Path does not exist!')
return None
# if the current node is the stop_node
# then we begin reconstructin the path from it to the start_no
de
if n == stop_node:
path = []
while parents[n] != n:
path.append(n)
n = parents[n]
path.append(start_node)
path.reverse()
print('Path found: {}'.format(path))
return path
# remove n from the open_list, and add it to closed_list
# because all of his neighbors were inspected
open_set.remove(n)
closed_set.add(n)
print('Path does not exist!')
return None
#define fuction to return neighbor and its distance
#from the passed node
def get_neighbors(v):
if v in Graph_nodes:
return Graph_nodes[v]
else:
return None
#for simplicity we ll consider heuristic distances given
#and this function returns heuristic distance for all nodes
def heuristic(n):
H_dist = {
'A': 11,
'B': 6,
'C': 99,
'D': 1,
'E': 7,
'G': 0,
}
return H_dist[n]
#Describe your graph here
Graph_nodes = {
'A': [('B', 2), ('E', 3)],
'B': [('C', 1),('G', 9)],
'C': None,
'E': [('D', 6)],
'D': [('G', 1)],
}
aStarAlgo('A', 'G')
Output:
Question # 03:
Solution:
We will apply Alpha Beta Pruning Algorithm on following example:
Step # 01:
We will first start with the initial move. We will initially define the alpha and beta values as the
worst case i.e. α = -∞ and β= +∞. We will prune the node only when alpha becomes greater than
or equal to beta.
Step # 02:
Since the initial value of alpha is less than beta so we didn’t prune it. Now it’s turn for MAX. So,
at node D, value of alpha will be calculated. The value of alpha at node D will be max (2, 3). So,
value of alpha at node D will be 3.
Step # 03:
Now the next move will be on node B and its turn for MIN now. So, at node B, the value of
alpha beta will be min (3, ∞). So, at node B values will be alpha= – ∞ and beta will be 3.
In the next step, algorithms traverse the next successor of Node B which is node E, and the
values of α= -∞, and β= 3 will also be passed.
Step # 04:
Now it’s turn for MAX. So, at node E we will look for MAX. The current value of alpha at E is –
∞ and it will be compared with 5. So, MAX (- ∞, 5) will be 5. So, at node E, alpha = 5, Beta = 5.
Now as we can see that alpha is greater than beta which is satisfying the pruning condition so we
can prune the right successor of node E and algorithm will not be traversed and the value at node
E will be 5.
Step # 05:
In the next step the algorithm again comes to node A from node B. At node A alpha will be
changed to maximum value as MAX (- ∞, 3). So now the value of alpha and beta at node A will
be (3, + ∞) respectively and will be transferred to node C. These same values will be transferred
to node F.
Step # 06:
At node F the value of alpha will be compared to the left branch which is 0. So, MAX (0, 3) will
be 3 and then compared with the right child which is 1, and MAX (3,1) = 3 still α remains 3, but
the node value of F will become 1.
Step # 07:
Now node F will return the node value 1 to C and will compare to beta value at C. Now its turn
for MIN. So, MIN (+ ∞, 1) will be 1. Now at node C, α= 3, and β= 1 and alpha is greater than
beta which again satisfies the pruning condition. So, the next successor of node C i.e. G will be
pruned and the algorithm didn’t compute the entire subtree G.
Step # 08:
Now, C will return the node value to A and the best value of A will be MAX (1, 3) will be 3.
The above represented tree is the final tree which is showing the nodes which are computed and
the nodes which are not computed. So, for this example the optimal value of the maximizer will
be 3.
Code:
# Initial values of Alpha and Beta
MAX, MIN = 1000, -1000
# Returns optimal value for current player
#(Initially called for root and maximizer)
def minimax(depth, nodeIndex, maximizingPlayer,
values, alpha, beta):
# Terminating condition. i.e
# leaf node is reached
if depth == 3:
return values[nodeIndex]
if maximizingPlayer:
best = MIN
# Recur for left and right children
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i,
False, values, alpha, beta)
best = max(best, val)
alpha = max(alpha, best)
# Alpha Beta Pruning
if beta <= alpha:
break
return best
else:
best = MAX
# Recur for left and
# right children
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i,
True, values, alpha, beta)
best = min(best, val)
beta = min(beta, best)
# Alpha Beta Pruning
if beta <= alpha:
break
return best
# Driver Code
if __name__ == "__main__":
values = [2, 3, 5, 9, 0, 1, 7, 5]
print("The optimal value is :", minimax(0, 0, True, values, MIN, MAX))