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

AI codes(1)

The document contains implementations of various graph search algorithms, including Depth-First Search (DFS), Depth-Limited Search (DLS), Depth-First Iterative Deepening (DFID), Breadth-First Search (BFS), Uniform Cost Search (UCS), Greedy Best-First Search (GBFS), and A* Search. Additionally, it discusses optimization techniques such as Genetic Algorithm (GA) and Hill Climbing for maximizing a fitness function. Each algorithm is demonstrated with example usage and outputs.

Uploaded by

kfortsec
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

AI codes(1)

The document contains implementations of various graph search algorithms, including Depth-First Search (DFS), Depth-Limited Search (DLS), Depth-First Iterative Deepening (DFID), Breadth-First Search (BFS), Uniform Cost Search (UCS), Greedy Best-First Search (GBFS), and A* Search. Additionally, it discusses optimization techniques such as Genetic Algorithm (GA) and Hill Climbing for maximizing a fitness function. Each algorithm is demonstrated with example usage and outputs.

Uploaded by

kfortsec
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

EXP 2

class Graph:
def __init__(self):
self.graph = {}

def add_edge(self, u, v):


"""Adds an edge between nodes u and v."""
if u not in self.graph:
self.graph[u] = []
self.graph[u].append(v)

def dfs(self, start, goal, visited=None):


"""Performs Depth-First Search (DFS) recursively."""
if visited is None:
visited = set()

visited.add(start)
print(start, end=" ")

if start == goal:
print("\nGoal found!")
return True

for neighbor in self.graph.get(start, []):


if neighbor not in visited:
if self.dfs(neighbor, goal, visited):
return True # Stop if goal is found
return False

def dls(self, start, goal, depth_limit, visited=None):


"""Performs Depth-Limited Search (DLS)."""
if visited is None:
visited = set()

visited.add(start)
print(start, end=" ")

if start == goal:
print("\nGoal found!")
return True

if depth_limit <= 0:
return False # Stop when depth limit is reached

for neighbor in self.graph.get(start, []):


if neighbor not in visited:
if self.dls(neighbor, goal, depth_limit - 1, visited):
return True # Stop if goal is found
return False

def dfid(self, start, goal, max_depth):


"""Performs Depth-First Iterative Deepening (DFID)."""
for depth in range(max_depth + 1):
print(f"\nTrying depth limit: {depth}")
visited = set()
if self.dls(start, goal, depth, visited):
return True
print("\nGoal not found within depth limit.")
return False

# Example Usage:
g = Graph()
g.add_edge('A', 'B')
g.add_edge('A', 'C')
g.add_edge('B', 'D')
g.add_edge('B', 'E')
g.add_edge('C', 'F')
g.add_edge('C', 'G')

print("DFS Traversal:")
g.dfs('A', 'G')

print("\n\nDLS Traversal (Depth Limit = 2):")


g.dls('A', 'G', 2)

print("\n\nDFID Traversal (Max Depth = 3):")


g.dfid('A', 'G', 3)
EXP 3
import heapq
from collections import deque

class Graph:
def __init__(self):
self.graph = {} # Adjacency list

def add_edge(self, u, v, cost=1):


"""Adds a directed edge from u to v with an optional cost (default = 1)."""
if u not in self.graph:
self.graph[u] = []
self.graph[u].append((v, cost))

def bfs(self, start, goal):


"""Performs Breadth-First Search (BFS) to find the shortest path (by edges)."""
queue = deque([(start, [start])]) # Stores (node, path)
visited = set()

while queue:
node, path = queue.popleft()
if node in visited:
continue
visited.add(node)

if node == goal:
print(f"BFS Path Found: {' → '.join(path)}")
return path # Return the first found path

for neighbor, _ in self.graph.get(node, []):


if neighbor not in visited:
queue.append((neighbor, path + [neighbor]))

print("BFS: No path found")


return None

def ucs(self, start, goal):


"""Performs Uniform Cost Search (UCS) to find the least-cost path."""
priority_queue = [(0, start, [start])] # (cost, node, path)
visited = {}

while priority_queue:
cost, node, path = heapq.heappop(priority_queue)

if node in visited and visited[node] <= cost:


continue
visited[node] = cost

if node == goal:
print(f"UCS Path Found: {' → '.join(path)} with Cost: {cost}")
return path, cost # Return path and cost

for neighbor, edge_cost in self.graph.get(node, []):


new_cost = cost + edge_cost
heapq.heappush(priority_queue, (new_cost, neighbor, path + [neighbor]))

print("UCS: No path found")


return None, float('inf')

# Example Usage:
g = Graph()
g.add_edge('A', 'B', 1)
g.add_edge('A', 'C', 4)
g.add_edge('B', 'D', 2)
g.add_edge('B', 'E', 5)
g.add_edge('C', 'F', 3)
g.add_edge('C', 'G', 7)
g.add_edge('D', 'H', 6)
g.add_edge('E', 'H', 4)
g.add_edge('F', 'H', 2)

print("\nBFS Search:")
g.bfs('A', 'H')

print("\nUCS Search:")
g.ucs('A', 'H')
EXP 4
import heapq

class Graph:
def __init__(self):
self.graph = {} # Adjacency list
self.heuristics = {} # Stores heuristic values for A* and GBFS

def add_edge(self, u, v, cost):


"""Adds a weighted edge between u and v."""
if u not in self.graph:
self.graph[u] = []
self.graph[u].append((v, cost))

def set_heuristic(self, node, value):


"""Assigns a heuristic value to a node."""
self.heuristics[node] = value

def greedy_best_first_search(self, start, goal):


"""Performs Greedy Best-First Search (GBFS) using heuristic h(n)."""
priority_queue = [(self.heuristics[start], start, [start])] # (h(n), node, path)
visited = set()

while priority_queue:
_, node, path = heapq.heappop(priority_queue)

if node in visited:
continue
visited.add(node)

if node == goal:
print(f"GBFS Path Found: {' → '.join(path)}")
return path # Return the first found path

for neighbor, _ in self.graph.get(node, []):


if neighbor not in visited:
heapq.heappush(priority_queue, (self.heuristics[neighbor], neighbor, path +
[neighbor]))

print("GBFS: No path found")


return None

def a_star_search(self, start, goal):


"""Performs A* Search using f(n) = g(n) + h(n)."""
priority_queue = [(self.heuristics[start], 0, start, [start])] # (f(n), g(n), node, path)
visited = {}

while priority_queue:
f, g, node, path = heapq.heappop(priority_queue)

if node in visited and visited[node] <= g:


continue
visited[node] = g
if node == goal:
print(f"A* Path Found: {' → '.join(path)} with Cost: {g}")
return path, g # Return path and cost

for neighbor, edge_cost in self.graph.get(node, []):


new_g = g + edge_cost
new_f = new_g + self.heuristics[neighbor]
heapq.heappush(priority_queue, (new_f, new_g, neighbor, path + [neighbor]))

print("A*: No path found")


return None, float('inf')

# Example Usage:
g = Graph()
g.add_edge('A', 'B', 1)
g.add_edge('A', 'C', 4)
g.add_edge('B', 'D', 2)
g.add_edge('B', 'E', 5)
g.add_edge('C', 'F', 3)
g.add_edge('C', 'G', 7)
g.add_edge('D', 'H', 6)
g.add_edge('E', 'H', 4)
g.add_edge('F', 'H', 2)

# Setting heuristic values (hypothetical estimated distances to goal H)


heuristics = {
'A': 10, 'B': 6, 'C': 8, 'D': 4, 'E': 4,
'F': 3, 'G': 7, 'H': 0 # Goal has heuristic 0
}

for node, h in heuristics.items():


g.set_heuristic(node, h)

print("\nGreedy Best-First Search:")


g.greedy_best_first_search('A', 'H')

print("\nA* Search:")
g.a_star_search('A', 'H')
EXP 5
import random
import numpy as np

# Objective function (maximize f(x) = x^2)


def fitness_function(x):
return x ** 2

# ---------- Genetic Algorithm (GA) ----------


def genetic_algorithm(pop_size=10, generations=50, mutation_rate=0.1):
# Generate initial population (random integers)
population = [random.randint(0, 100) for _ in range(pop_size)]

for gen in range(generations):


# Evaluate fitness
fitness_values = [fitness_function(x) for x in population]

# Selection (Tournament Selection)


selected = random.choices(population, weights=fitness_values, k=pop_size // 2)

# Crossover (Single Point Crossover)


offspring = []
for _ in range(len(selected) // 2):
p1, p2 = random.sample(selected, 2)
crossover_point = random.randint(1, len(bin(p1)) - 2)
mask = (1 << crossover_point) - 1
child1 = (p1 & mask) | (p2 & ~mask)
child2 = (p2 & mask) | (p1 & ~mask)
offspring.extend([child1, child2])

# Mutation (Bit Flip Mutation)


for i in range(len(offspring)):
if random.random() < mutation_rate:
bit = 1 << random.randint(0, len(bin(offspring[i])) - 2)
offspring[i] ^= bit # Flip bit

# New population
population = selected + offspring

# Return the best solution


best_solution = max(population, key=fitness_function)
return best_solution, fitness_function(best_solution)

# ---------- Hill Climbing ----------


def hill_climbing(start_x=10, max_iterations=100, step_size=1):
current_x = start_x
current_fitness = fitness_function(current_x)

for _ in range(max_iterations):
# Generate a random neighbor
neighbor = current_x + random.choice([-step_size, step_size])

# Evaluate fitness
neighbor_fitness = fitness_function(neighbor)

# If the neighbor is better, move to it


if neighbor_fitness > current_fitness:
current_x, current_fitness = neighbor, neighbor_fitness

return current_x, current_fitness

# Run Genetic Algorithm


best_ga, best_ga_fitness = genetic_algorithm()
print(f"Genetic Algorithm Best Solution: x = {best_ga}, Fitness = {best_ga_fitness}")

# Run Hill Climbing


best_hc, best_hc_fitness = hill_climbing()
print(f"Hill Climbing Best Solution: x = {best_hc}, Fitness = {best_hc_fitness}")

You might also like