0% found this document useful (0 votes)
4 views

AI Lab

The document contains implementations of various algorithms and problems in Python, including Breadth-First Search (BFS), Depth-First Search (DFS), the Traveling Salesman Problem, Simulated Annealing, the Wumpus Problem, and the 8-puzzle problem. Each section provides a class structure and methods to execute the respective algorithms, demonstrating their functionality through driver code. These implementations serve as examples for understanding graph traversal, optimization techniques, and problem-solving in artificial intelligence.

Uploaded by

s.dineshwar1231
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

AI Lab

The document contains implementations of various algorithms and problems in Python, including Breadth-First Search (BFS), Depth-First Search (DFS), the Traveling Salesman Problem, Simulated Annealing, the Wumpus Problem, and the 8-puzzle problem. Each section provides a class structure and methods to execute the respective algorithms, demonstrating their functionality through driver code. These implementations serve as examples for understanding graph traversal, optimization techniques, and problem-solving in artificial intelligence.

Uploaded by

s.dineshwar1231
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 23

1.

BFS
from collections import defaultdict

# This class represents a directed graph


# using adjacency list representation
class Graph:

# Constructor
def __init__(self):

# Default dictionary to store graph


self.graph = defaultdict(list)

# Function to add an edge to graph


def addEdge(self, u, v):
self.graph[u].append(v)

# Function to print a BFS of graph


def BFS(self, s):

# Mark all the vertices as not visited


visited = [False] * (max(self.graph) + 1)

# Create a queue for BFS


queue = []

# Mark the source node as


# visited and enqueue it
queue.append(s)
visited[s] = True

while queue:
# Dequeue a vertex from
# queue and print it
s = queue.pop(0)
print(s, end=" ")

# Get all adjacent vertices of the


# dequeued vertex s.
# If an adjacent has not been visited,
# then mark it visited and enqueue it
for i in self.graph[s]:
if not visited[i]:
queue.append(i)
visited[i] = True

# Driver code
if __name__ == '__main__':

# Create a graph given in


# the above diagram
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)

print("Following is Breadth First Traversal"


" (starting from vertex 2)")
g.BFS(2)
Output:

2. DFS
# Python3 program to print DFS traversal
# from a given graph
from collections import defaultdict

# This class represents a directed graph using


# adjacency list representation
class Graph:

# Constructor
def __init__(self):

# Default dictionary to store graph


self.graph = defaultdict(list)

# Function to add an edge to graph


def addEdge(self, u, v):
self.graph[u].append(v)

# A function used by DFS


def DFSUtil(self, v, visited):

# Mark the current node as visited


# and print it
visited.add(v)
print(v, end=' ')

# Recur for all the vertices


# adjacent to this vertex
for neighbour in self.graph[v]:
if neighbour not in visited:
self.DFSUtil(neighbour, visited)

# The function to do DFS traversal. It uses


# recursive DFSUtil()
def DFS(self, v):

# Create a set to store visited vertices


visited = set()

# Call the recursive helper function


# to print DFS traversal
self.DFSUtil(v, visited)

# Driver's code
if __name__ == "__main__":
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)

print("Following is Depth First Traversal (starting from vertex 2)")


# Function call
g.DFS(2)

Output:

3. Travelling Salesperson Problem

# Python3 program to implement traveling salesman


# problem using naive approach.
from sys import maxsize
from itertools import permutations
V=4

# implementation of traveling Salesman Problem


def travellingSalesmanProblem(graph, s):

# store all vertex apart from source vertex


vertex = []
for i in range(V):
if i != s:
vertex.append(i)

# store minimum weight Hamiltonian Cycle


min_path = maxsize
next_permutation=permutations(vertex)
for i in next_permutation:

# store current Path weight(cost)


current_pathweight = 0

# compute current path weight


k=s
for j in i:
current_pathweight += graph[k][j]
k=j
current_pathweight += graph[k][s]

# update minimum
min_path = min(min_path, current_pathweight)

return min_path
# Driver Code
if __name__ == "__main__":

# matrix representation of graph


graph = [[0, 10, 15, 20], [10, 0, 35, 25],
[15, 35, 0, 30], [20, 25, 30, 0]]
s=0
print(travellingSalesmanProblem(graph, s))

4. Implementation of Simulated Annealing


import math
import random

# Objective function: Rastrigin function


def objective_function(x):
return 10 * len(x) + sum([(xi**2 - 10 * math.cos(2 * math.pi * xi)) for xi
in x])

# Neighbor function: small random change


def get_neighbor(x, step_size=0.1):
neighbor = x[:]
index = random.randint(0, len(x) - 1)
neighbor[index] += random.uniform(-step_size, step_size)
return neighbor

# Simulated Annealing function


def simulated_annealing(objective, bounds, n_iterations, step_size, temp):
# Initial solution
best = [random.uniform(bound[0], bound[1]) for bound in bounds]
best_eval = objective(best)
current, current_eval = best, best_eval
scores = [best_eval]

for i in range(n_iterations):
# Decrease temperature
t = temp / float(i + 1)
# Generate candidate solution
candidate = get_neighbor(current, step_size)
candidate_eval = objective(candidate)
# Check if we should keep the new solution
if candidate_eval < best_eval or random.random() <
math.exp((current_eval - candidate_eval) / t):
current, current_eval = candidate, candidate_eval
if candidate_eval < best_eval:
best, best_eval = candidate, candidate_eval
scores.append(best_eval)

# Optional: print progress


if i % 100 == 0:
print(f"Iteration {i}, Temperature {t:.3f}, Best Evaluation
{best_eval:.5f}")

return best, best_eval, scores

# Define problem domain


bounds = [(-5.0, 5.0) for _ in range(2)] # for a 2-dimensional Rastrigin
function
n_iterations = 1000
step_size = 0.1
temp = 10

# Perform the simulated annealing search


best, score, scores = simulated_annealing(objective_function, bounds,
n_iterations, step_size, temp)

print(f'Best Solution: {best}')


print(f'Best Score: {score}')

5. Wumpus Problem

class Agent:
def __init__(self):
self.__wumpusWorld = [
['','','P',''], # Rooms [1,1] to [4,1]
['','','',''], # Rooms [1,2] to [4,2]
['W','','',''], # Rooms [1,3] to [4,3]
['','','',''], # Rooms [1,4] to [4,4]
] # This is the wumpus world shown in the assignment question.
# A different instance of the wumpus world will be used for
evaluation.
self.__curLoc = [1,1]
self.__isAlive = True
self.__hasExited = False

def __FindIndicesForLocation(self,loc):
x,y = loc
i,j = y-1, x-1
return i,j

def __CheckForPitWumpus(self):
ww = self.__wumpusWorld
i,j = self.__FindIndicesForLocation(self.__curLoc)
if 'P' in ww[i][j] or 'W' in ww[i][j]:
print(ww[i][j])
self.__isAlive = False
print('Agent is DEAD.')
return self.__isAlive

def TakeAction(self,action): # The function takes an action and returns


whether the Agent is alive
# after taking the action.
validActions = ['Up','Down','Left','Right']
assert action in validActions, 'Invalid Action.'
if self.__isAlive == False:
print('Action cannot be performed. Agent is DEAD. Location:
{0}'.format(self.__curLoc))
return False
if self.__hasExited == True:
print('Action cannot be performed. Agent has exited the Wumpus
world.'.format(self.__curLoc))
return False

index = validActions.index(action)
validMoves = [[0,1],[0,-1],[-1,0],[1,0]]
move = validMoves[index]
newLoc = []
for v, inc in zip(self.__curLoc,move):
z = v + inc #increment location index
z = 4 if z>4 else 1 if z<1 else z #Ensure that index is between 1
and 4

newLoc.append(z)
self.__curLoc = newLoc
print('Action Taken: {0}, Current Location
{1}'.format(action,self.__curLoc))
if self.__curLoc[0]==4 and self.__curLoc[1]==4:
self.__hasExited=True
return self.__CheckForPitWumpus()

def __FindAdjacentRooms(self):
cLoc = self.__curLoc
validMoves = [[0,1],[0,-1],[-1,0],[1,0]]
adjRooms = []
for vM in validMoves:
room = []
valid = True
for v, inc in zip(cLoc,vM):
z = v + inc
if z<1 or z>4:
valid = False
break
else:
room.append(z)
if valid==True:
adjRooms.append(room)
return adjRooms

def PerceiveCurrentLocation(self): #This function perceives the current


location.
#It tells whether breeze and stench are present
in the current location.
breeze, stench = False, False
ww = self.__wumpusWorld
if self.__isAlive == False:
print('Agent cannot perceive. Agent is DEAD. Location:
{0}'.format(self.__curLoc))
return [None,None]
if self.__hasExited == True:
print('Agent cannot perceive. Agent has exited the Wumpus
World.'.format(self.__curLoc))
return [None,None]

adjRooms = self.__FindAdjacentRooms()
for room in adjRooms:
i,j = self.__FindIndicesForLocation(room)
if 'P' in ww[i][j]:
breeze = True
if 'W' in ww[i][j]:
stench = True
return [breeze,stench]

def FindCurrentLocation(self):
return self.__curLoc

def main():
ag = Agent()

print('curLoc',ag.FindCurrentLocation())
print('Percept [breeze, stench] :',ag.PerceiveCurrentLocation())
ag.TakeAction('Right')
print('Percept',ag.PerceiveCurrentLocation())
ag.TakeAction('Right')
print('Percept',ag.PerceiveCurrentLocation())
ag.TakeAction('Right')
print('Percept',ag.PerceiveCurrentLocation())
ag.TakeAction('Up')
print('Percept',ag.PerceiveCurrentLocation())
ag.TakeAction('Up')
print('Percept',ag.PerceiveCurrentLocation())
ag.TakeAction('Up')
print('Percept',ag.PerceiveCurrentLocation())

if __name__=='__main__':
main()

6. 8 puzzle Problem
# Python code to display the way from the root
# node to the final destination node for N*N-1 puzzle
# algorithm by the help of Branch and Bound technique
# The answer assumes that the instance of the
# puzzle can be solved

# Importing the 'copy' for deepcopy method


import copy

# Importing the heap methods from the python


# library for the Priority Queue
from heapq import heappush, heappop

# This particular var can be changed to transform


# the program from 8 puzzle(n=3) into 15
# puzzle(n=4) and so on ...
n=3

# bottom, left, top, right


rows = [ 1, 0, -1, 0 ]
cols = [ 0, -1, 0, 1 ]

# creating a class for the Priority Queue


class priorityQueue:

# Constructor for initializing a


# Priority Queue
def __init__(self):
self.heap = []

# Inserting a new key 'key'


def push(self, key):
heappush(self.heap, key)

# funct to remove the element that is minimum,


# from the Priority Queue
def pop(self):
return heappop(self.heap)

# funct to check if the Queue is empty or not


def empty(self):
if not self.heap:
return True
else:
return False

# structure of the node


class nodes:

def __init__(self, parent, mats, empty_tile_posi,


costs, levels):

# This will store the parent node to the


# current node And helps in tracing the
# path when the solution is visible
self.parent = parent

# Useful for Storing the matrix


self.mats = mats

# useful for Storing the position where the


# empty space tile is already existing in the matrix
self.empty_tile_posi = empty_tile_posi

# Store no. of misplaced tiles


self.costs = costs

# Store no. of moves so far


self.levels = levels

# This func is used in order to form the


# priority queue based on
# the costs var of objects
def __lt__(self, nxt):
return self.costs < nxt.costs

# method to calc. the no. of


# misplaced tiles, that is the no. of non-blank
# tiles not in their final posi
def calculateCosts(mats, final) -> int:

count = 0
for i in range(n):
for j in range(n):
if ((mats[i][j]) and
(mats[i][j] != final[i][j])):
count += 1

return count

def newNodes(mats, empty_tile_posi, new_empty_tile_posi,


levels, parent, final) -> nodes:

# Copying data from the parent matrixes to the present matrixes


new_mats = copy.deepcopy(mats)

# Moving the tile by 1 position


x1 = empty_tile_posi[0]
y1 = empty_tile_posi[1]
x2 = new_empty_tile_posi[0]
y2 = new_empty_tile_posi[1]
new_mats[x1][y1], new_mats[x2][y2] = new_mats[x2][y2],
new_mats[x1][y1]

# Setting the no. of misplaced tiles


costs = calculateCosts(new_mats, final)

new_nodes = nodes(parent, new_mats, new_empty_tile_posi,


costs, levels)
return new_nodes
# func to print the N by N matrix
def printMatsrix(mats):

for i in range(n):
for j in range(n):
print("%d " % (mats[i][j]), end = " ")

print()

# func to know if (x, y) is a valid or invalid


# matrix coordinates
def isSafe(x, y):

return x >= 0 and x < n and y >= 0 and y < n

# Printing the path from the root node to the final node
def printPath(root):

if root == None:
return

printPath(root.parent)
printMatsrix(root.mats)
print()

# method for solving N*N - 1 puzzle algo


# by utilizing the Branch and Bound technique. empty_tile_posi is
# the blank tile position initially.
def solve(initial, empty_tile_posi, final):

# Creating a priority queue for storing the live


# nodes of the search tree
pq = priorityQueue()

# Creating the root node


costs = calculateCosts(initial, final)
root = nodes(None, initial,
empty_tile_posi, costs, 0)

# Adding root to the list of live nodes


pq.push(root)

# Discovering a live node with min. costs,


# and adding its children to the list of live
# nodes and finally deleting it from
# the list.
while not pq.empty():

# Finding a live node with min. estimatsed


# costs and deleting it form the list of the
# live nodes
minimum = pq.pop()

# If the min. is ans node


if minimum.costs == 0:

# Printing the path from the root to


# destination;
printPath(minimum)
return

# Generating all feasible children


for i in range(n):
new_tile_posi = [
minimum.empty_tile_posi[0] + rows[i],
minimum.empty_tile_posi[1] + cols[i], ]

if isSafe(new_tile_posi[0], new_tile_posi[1]):

# Creating a child node


child = newNodes(minimum.mats,
minimum.empty_tile_posi,
new_tile_posi,
minimum.levels + 1,
minimum, final,)

# Adding the child to the list of live nodes


pq.push(child)

# Main Code

# Initial configuration
# Value 0 is taken here as an empty space
initial = [ [ 1, 2, 3 ],
[ 5, 6, 0 ],
[ 7, 8, 4 ] ]

# Final configuration that can be solved


# Value 0 is taken as an empty space
final = [ [ 1, 2, 3 ],
[ 5, 8, 6 ],
[ 0, 7, 4 ] ]

# Blank tile coordinates in the


# initial configuration
empty_tile_posi = [ 1, 2 ]

# Method call for solving the puzzle


solve(initial, empty_tile_posi, final)
7. Towers of Hanoi
def tower_of_hanoi(disks, source, auxiliary, target):
# Base case: If there's only one disk, move it directly from source to
target
if disks == 1:
print('Move disk 1 from rod {} to rod {}.'.format(source, target))
return
# Move the top (n-1) disks from source to auxiliary, using target as
auxiliary
tower_of_hanoi(disks - 1, source, target, auxiliary)
# Move the nth disk from source to target
print('Move disk {} from rod {} to rod {}.'.format(disks, source, target))
# Move the (n-1) disks from auxiliary to target, using source as auxiliary
tower_of_hanoi(disks - 1, auxiliary, source, target)

# Input number of disks


disks = int(input('Enter the number of disks: '))
# Calling the function: source=A, auxiliary=B, target=C
tower_of_hanoi(disks, 'A', 'B', 'C')
8. Implement A* algorithm
from queue import PriorityQueue

# Creating Base Class


class State(object):
def __init__(self, value, parent, start=0, goal=0):
self.children = []
self.parent = parent
self.value = value
self.dist = 0
if parent:
self.start = parent.start
self.goal = parent.goal
self.path = parent.path[:]
self.path.append(value)
else:
self.path = [value]
self.start = start
self.goal = goal

def GetDistance(self):
pass

def CreateChildren(self):
pass
# Creating subclass
class State_String(State):
def __init__(self, value, parent, start=0, goal=0):
super(State_String, self).__init__(value, parent, start, goal)
self.dist = self.GetDistance()

def GetDistance(self):
if self.value == self.goal:
return 0
dist = 0
for i in range(len(self.goal)):
letter = self.goal[i]
if letter in self.value:
dist += abs(i - self.value.index(letter))
else:
dist += len(self.goal) # Penalty if letter is not in the string
return dist

def CreateChildren(self):
if not self.children:
for i in range(len(self.value) - 1):
val = list(self.value)
# Swap adjacent letters
val[i], val[i + 1] = val[i + 1], val[i]
child = State_String("".join(val), self)
self.children.append(child)

# Creating a class that holds the final magic


class A_Star_Solver:
def __init__(self, start, goal):
self.path = []
self.visitedQueue = []
self.priorityQueue = PriorityQueue()
self.start = start
self.goal = goal

def Solve(self):
startState = State_String(self.start, None, self.start, self.goal)
count = 0
self.priorityQueue.put((0, count, startState))

while not self.path and not self.priorityQueue.empty():


closestChild = self.priorityQueue.get()[2]
closestChild.CreateChildren()
self.visitedQueue.append(closestChild.value)

for child in closestChild.children:


if child.value not in self.visitedQueue:
count += 1
if not child.dist:
self.path = child.path
break
self.priorityQueue.put((child.dist, count, child))

if not self.path:
print("Goal is not possible: " + self.goal)
return self.path

# Calling all the existing stuff


if __name__ == "__main__":
start1 = "path"
goal1 = "hpta"
print("Starting....")
a = A_Star_Solver(start1, goal1)
result_path = a.Solve()
for i in range(len(result_path)):
print("{0}) {1}".format(i, result_path[i]))

9. Hill Climbing Algorithm


import random

def randomSolution(tsp):
cities = list(range(len(tsp)))
solution = []
for i in range(len(tsp)):
randomCity = cities[random.randint(0, len(cities) - 1)]
solution.append(randomCity)
cities.remove(randomCity)
return solution

def routeLength(tsp, solution):


route_length = 0
for i in range(len(solution)):
route_length += tsp[solution[i - 1]][solution[i]]
return route_length

def getNeighbours(solution):
neighbours = []
for i in range(len(solution)):
for j in range(i + 1, len(solution)):
neighbour = solution.copy()
neighbour[i], neighbour[j] = neighbour[j], neighbour[i] # Swap two cities
neighbours.append(neighbour)
return neighbours

def getBestNeighbour(tsp, neighbours):


bestRouteLength = routeLength(tsp, neighbours[0])
bestNeighbour = neighbours[0]

for neighbour in neighbours:


currentRouteLength = routeLength(tsp, neighbour)
if currentRouteLength < bestRouteLength:
bestRouteLength = currentRouteLength
bestNeighbour = neighbour

return bestNeighbour, bestRouteLength

def hillClimbing(tsp):
currentSolution = randomSolution(tsp)
currentRouteLength = routeLength(tsp, currentSolution)

while True:
neighbours = getNeighbours(currentSolution)
bestNeighbour, bestNeighbourRouteLength = getBestNeighbour(tsp,
neighbours)

if bestNeighbourRouteLength < currentRouteLength:


currentSolution = bestNeighbour
currentRouteLength = bestNeighbourRouteLength
else:
break # Stop if no better neighbour is found

return currentSolution, currentRouteLength


def main():
tsp = [
[0, 400, 500, 300],
[400, 0, 300, 500],
[500, 300, 0, 400],
[300, 500, 400, 0]
]
solution, length = hillClimbing(tsp)
print("Best solution:", solution)
print("Route length:", length)

if __name__ == "__main__":
main()

10.
def greet(bot_name, birth_year):
print("Hello! My name is {0}.".format(bot_name))
print("I was created in {0}.".format(birth_year))

def remind_name():
print('Please, remind me your name.')
name = input()
print("What a great name you have, {0}!".format(name))

def provide_information():
while True:
print("What information would you like to know?")
print("1. Courses offered this semester")
print("2. Next campus event")
print("3. How to apply for financial aid")
print("4. College facilities")
print("5. Student organizations")

choice = int(input("Enter your choice (1-5): "))

if choice == 1:
print("This semester, we offer the following courses:")
print("- Mathematics 101")
print("- Introduction to Computer Science")
print("- English Literature")
print("- Biology 101")
print("- History of Art")
elif choice == 2:
print("The next campus event is the career fair on March 15th from 10
AM to 4 PM in the Student Center.")
elif choice == 3:
print("To apply for financial aid, visit the Financial Aid Office or check our
website for scholarship opportunities.")
elif choice == 4:
print("Our college has the following facilities:")
print("- Library")
print("- Gymnasium")
print("- Student Lounge")
print("- Computer Lab")
print("- Cafeteria")
elif choice == 5:
print("Here are some popular student organizations:")
print("- Coding Club")
print("- Art Society")
print("- Debate Team")
print("- Environmental Club")
else:
print("I’m sorry, I didn’t understand that.")

# Ask if they want more information or to exit


continue_choice = input("Would you like to ask another question? (yes/no):
").strip().lower()
if continue_choice != 'yes':
print("Exiting.")
break
def end():
print('Congratulations, have a nice day!')
input()

# Start of the program


greet('CollegeInfoBot', '2024') # Change as needed
remind_name()
provide_information()
end()

You might also like