FA17-BCS-027 Lab
FA17-BCS-027 Lab
FA17-BCS-027 Lab
Name:
MUHAMMAD TALHA BIN TUFAIL
Reg No:
FA17-BCS-027
Submitted To:
SIR WAQAR
Dated:
23 NOVEMBER,2020
Greedy best-first search algorithm always selects the path which appears best at that
moment. It is the combination of depth-first search and breadth-first search algorithms. It
uses the heuristic function and search. Best-first search allows us to take the advantages
of both algorithms.
f(n)= g(n)
A* search is the most known form of best-first search. It uses heuristic function h(n), and
cost to reach the node n from the start state g(n). It has combined features of UCS and
greedy best-first search so we can solve the problem efficiently using the A* Search
Algorithm
Uninformed Searches:
Uninformed search is a class of general-purpose search algorithms which operates in brute force-
way. Uninformed search algorithms do not have additional information about state or search
space other than how to traverse the tree, so it is also called blind search. Types of uninformed
searches:
1. Breadth-first Search
2. Depth-first Search
3. Depth-limited Search
4. Iterative deepening depth-first search
5. Uniform cost search
6. Bidirectional Search
Breadth-first Search:
Breadth-first search is the most common search strategy for traversing a tree or graph.
This algorithm searches breadthwise in a tree or graph, so it is called breadth-first search.
BFS algorithm starts searching from the root node of the tree and expands all successor
node at the current level before moving to nodes of next level.
Depth-first Search:
Depth-first search is a recursive algorithm for traversing a tree or graph data structure. It
is called the depth-first search because it starts from the root node and follows each path
to its greatest depth node before moving to the next path. DFS uses a stack data structure
for its implementation.
Depth-limited Search:
A depth-limited search algorithm is like depth-first search with a predetermined limit.
Depth-limited search can solve the drawback of the infinite path in the Depth-first search
Bidirectional Search:
Bidirectional search algorithm runs two simultaneous searches, one form initial state
called as forward-search and other from goal node called as backward-search, to find the
goal node.
Uniform-cost search is a searching algorithm used for traversing a weighted tree or graph. This
algorithm comes into play when a different cost is available for each edge. The primary goal of
the uniform-cost search is to find a path to the goal node which has the lowest cost. Uniform-cost
search expands nodes according to their path costs form the root node. It can be used to solve
any graph and tree where the optimal cost is in demand. A uniform-cost search algorithm is
implemented by the priority queue.
Advantages:
Uniform cost search is optimal because at every state the path with the least cost is
chosen.
Disadvantages:
It does not care about the number of steps involve in searching and only concerned
about path cost. Due to which this algorithm may be stuck in an infinite loop.
Example:
(3) What is Bidirectional search Algorithm?
Bidirectional search algorithm runs two simultaneous searches, one form initial state called as
forward-search and other from goal node called as backward-search, to find the goal node.
Bidirectional search replaces one single search graph with two small subgraphs in which one
starts the search from an initial vertex and other starts from goal vertex. The search stops when
these two graphs intersect each other.
Advantages:
Disadvantages:
Example:
(4) Difference between graph and tree traversal?
Heuristic search refers to a search strategy that attempts to optimize a problem by iteratively
improving the solution based on a given heuristic function or a cost measure. A heuristic
search method does not always guarantee to find an optimal or the best solution but may
instead find a good or acceptable solution within a reasonable amount of time and memory
space. The commonly used heuristic search method including the hill climbing method, BFS
and A star algorithm
(6) What are adversarial searches?
Adversarial searches are those in which the opponent and enemy are the changing the state of the
problem which can degrade the performance other player. Adversarial search is a search, where
we examine the problem which arises when we try to plan of the world and other agents are
planning against us.
Min-Max
Alpha-beta pruning
Write the code of searches mention below with choosing any random graph
from internet/book examples. Also write short introduction of all five searches
with the screen shot of its output. Make user dependent of all the code of
searches.
Depth-Limited Search:
Definition:
A depth-limited search algorithm is like depth-first search with a predetermined limit. Depth-
limited search can solve the drawback of the infinite path in the Depth-first search. In this
algorithm, the node at the depth limit will treat as it has no successor nodes further.
Code:
# Constructor
def __init__(self,vertices):
self.ver=vertices
self.graph = defaultdict(list)
for i in self.graph[source]:
if(self.DLS(i,target,depth-1)):
return True
return False
for i in range(total_vertices):
num1=int(input("Enter the first edge"))
num2=int(input("Enter the Second edge"))
g.addEdge(num1,num2)
if g.IDDFS(source,target,depth)== True:
print("The target is reachable ")
else:
print("The target is not reachable ")
Output:
Definition:
The iterative deepening algorithm is a combination of DFS and BFS algorithms. This search
algorithm finds out the best depth limit and does it by gradually increasing the limit until a goal
is found. This algorithm performs depth-first search up to a certain "depth limit", and it keeps
increasing the depth limit after each iteration until the goal node is found.
Code:
class Graph:
def __init__(self,vertices):
self.ver=vertices
self.graph = defaultdict(list)
for i in self.graph[source]:
if(self.DLS(i,target,depth-1)):
return True
return False
for i in range(total_vertices):
num1=int(input("Enter the first edge : "))
num2=int(input("Enter the Second edge : "))
g.addEdge(num1,num2)
source=int(input("Enter the source value : "))
target=int(input("Enter the target value : "))
depth=int(input("Enter the depth value : "))
else:
print("The target is reachable : " , +depth)
break
else:
A star Search:
Definition
A* search is the most known form of best-first search. It uses heuristic function h(n), and cost to
reach the node n from the start state g(n). It has combined features of UCS and greedy best-first
search, by which it solves the problem efficiently. A* search algorithm finds the shortest path
through the search space using the heuristic function. This search algorithm expands less search
tree and provides optimal result faster. A* algorithm is like UCS except that it uses g(n)+h(n)
instead of g(n).
Code:
class AStarGraph(object):
def __init__(self):
self.barriers = []
t=int(input("Enter total number of barriers : "))
for i in range(t):
x=int(input("Enter the row value :"))
y=int(input("Enter the column value :" ))
self.barriers.append(
[x,y])
D = 1
D2 = 1
dx = abs(start[0] - goal[0])
dy = abs(start[1] - goal[1])
return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
closedVertices = set()
openVertices = set([start])
cameFrom = {}
if __name__ == "__main__":
graph = AStarGraph()
s1=int(input("Enter the row number for start:"))
s2=int(input("Enter the column number for start : "))
g1=int(input("Enter the row number for goal :"))
g2=int(input("Enter the column number for goal :"))
result, cost = AStarSearch((s1,s2), (g1, g2), graph)
print("route", result)
print("cost", cost)
output:
Genetic Algorithm:
Definition
Code:
import random
# Valid genes
GENES = '''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
QRSTUVWXYZ 1234567890, .-;:_!"#%&/()=?@${[]}'''
class Individual(object):
'''
Class representing individual in population
'''
@classmethod
def mutated_genes(self):
'''
create random genes for mutation
'''
global GENES
gene = random.choice(GENES)
return gene
@classmethod
def create_gnome(self):
'''
create chromosome or string of genes
'''
global TARGET
gnome_len = len(TARGET)
return [self.mutated_genes() for _ in range(gnome_len)]
# random probability
prob = random.random()
def cal_fitness(self):
'''
Calculate fittness score, it is the number of
characters in string which differ from target
string.
'''
global TARGET
fitness = 0
for gs, gt in zip(self.chromosome, TARGET):
if gs != gt: fitness += 1
return fitness
# Driver code
def main():
global POPULATION_SIZE
# current generation
generation = 1
found = False
population = []
population = new_generation
generation += 1
if __name__ == '__main__':
main()
output:
Min-Max:
Code:
if (maxTurn):
return max(minimax(curDepth + 1, nodeIndex * 2,
False, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1,
False, scores, targetDepth))
else:
return min(minimax(curDepth + 1, nodeIndex * 2,
True, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1,
True, scores, targetDepth))
# Driver code
scores=[]
x=int(input("Enter the total number of leafs :"))
for i in range(x):
y=int(input("Enter leaf value : "))
scores.append(y)
curDepth=int(input("Enter the depth value : "))
nodeIndex=int(input("Enter the node value : "))
maxt=True
treeDepth = math.log(len(scores), 2)
Output :
Alpha -beta pruning:
Code:
if maximizingPlayer:
best = MIN
return best
else:
best = MAX
return best
# Driver Code
if __name__ == "__main__":
values = []
x = int(input("Enter the total number of leafs :"))
for i in range(x):
y = int(input("Enter node value : "))
values.append(y)
Output:
Hill climbing algorithm is a local search algorithm which continuously moves in the direction of
increasing elevation/value to find the peak of the mountain or best solution to the problem. It
terminates when it reaches a peak value where no neighbor has a higher value.
Code:
output: