Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

Department of Information Technology

Bachelor of Technology
in
Information Technology

IT306-Artificial Intelligence

Submitted To: Submitted By:


Ms.Reena Tripathi Unmik Gyawali
(IT dept.) (2K20/IT/154)

Delhi Technological University


(Formerly Delhi College of Engineering)
Bawana Road, Delhi-110042
S.N. Assignment Date

1 Write a program to demonstrate basic array characteristics using numpy 16/01/23

2 1) Write down two intelligent programs for the TIC-TAC-TOE problem. 2) 23/01/23
Write down a program to implement Breadth-first search and depth-first
search for the water jug problem

3 1) Implement Best first search and least cost search for 8-Puzzle problem. 2) 29/01/23
Implement the steps of A* Algorithms for 8-Puzzle problem

4 Write a program to implement the DFS(depth-first search) algorithm in 27/02/23


python.

5 Implement the hill climbing algorithm in python. 27/02/23

6 Write a program to implement a neural network in Python 6/03/23

7 Compare the different search algorithms. 27/03/23

8 WAP to implement factorial, Fibonacci of a given number in PROLOG. 27/03/23

9 Write a program to solve 4-Queen problem in PROLOG 10/4/23


2K20/IT/154
Assignment 1
Write a program to demonstrate basic array characteristics using numpy:
● Learn basic about numpy, Arrays in Numpy
● Write a program to create a Numpy Array
● Accessing the array index
● Perform basic addition (adding 1 to every element) and subtraction (subtracting 2 from each
element) operation.
● Learn Data Types in Numpy
● Write a program to construct a data type object
● Learn different Methods in Numpy (Implement 10 methods)
● Find unique elements in the array using numpy.

NumPy is a powerful Python library used for scientific computing and data analysis. It provides support
for arrays and matrices, which are the basic data structures used for numerical calculations. Here are some
basic characteristics of NumPy:

1. Array Creation: NumPy provides a convenient way to create arrays of various sizes and dimensions.
You can create arrays from Python lists, tuples, and other iterable objects using the `numpy.array()`
function.

2. Array Manipulation: NumPy allows you to manipulate arrays in various ways. You can reshape, slice,
and concatenate arrays using the built-in functions provided by NumPy.

3. Mathematical Operations: NumPy provides a wide range of mathematical functions for performing
basic arithmetic, trigonometric, logarithmic, and statistical operations on arrays.

4. Broadcasting: NumPy allows you to perform operations on arrays of different shapes and sizes using a
technique called broadcasting.

5. Indexing and Slicing: NumPy provides powerful indexing and slicing capabilities for accessing and
manipulating elements of arrays.

6. Universal Functions: NumPy provides a large number of universal functions that operate on entire
arrays rather than individual elements.

7. Linear Algebra: NumPy provides a comprehensive set of linear algebra functions for solving linear
equations, eigenvalue problems, and other matrix operations.

8. Random Number Generation: NumPy provides functions for generating random numbers and random
arrays using various distributions.

Overall, NumPy is a powerful library for numerical computing and data analysis in Python, and it has
become a standard tool for scientific computing in Python.
1/29/23, 6:08 PM IT_154_AIES_1

In [1]:
import numpy as np

In [2]:
arr = np.array([1, 2, 3, 4, 5])

print(arr)

print(type(arr))

[1 2 3 4 5]
<class 'numpy.ndarray'>

In [3]:
print(arr[2] + arr[3])

In [4]:
print(np.add(1, arr[:]))

[2 3 4 5 6]

In [5]:
print(np.subtract(arr[:], 2))

[-1 0 1 2 3]

In [6]:
print(arr.dtype)

int32

In [7]:
a = np.array(['apple', 'banana', 'cherry'])

print(a.dtype)

<U6

In [8]:
b = np.array([True,True,False])

print(b.dtype)

bool

In [9]:
a = [1, 2, 2, 4, 3, 6, 4, 8]

c = np.unique(a)

print(c)

[1 2 3 4 6 8]

In [10]:
dt = np.dtype('>i4')
print(dt)
print("Byte order is:",dt.byteorder)

print("Size is:",dt.itemsize)

localhost:8890/nbconvert/html/IT_154_AIES_1.ipynb?download=false 1/3
1/29/23, 6:08 PM IT_154_AIES_1

print("Data type is:",dt.name)


>i4
Byte order is: >
Size is: 4
Data type is: int32

In [11]:
x = arr.copy()
arr[0] = 42

print(arr)
print(x)

[42 2 3 4 5]
[1 2 3 4 5]

In [12]:
x = arr.view()
arr[0] = 32

print(arr)
print(x)

[32 2 3 4 5]
[32 2 3 4 5]

In [13]:
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])

print(arr.shape)

(2, 4)

In [14]:
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

newarr = arr.reshape(4, 3)
print(arr)
print(newarr)

[ 1 2 3 4 5 6 7 8 9 10 11 12]
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]

In [15]:
for x in arr:
print(x)

1
2
3
4
5
6
7
8
9
10
11
12

localhost:8890/nbconvert/html/IT_154_AIES_1.ipynb?download=false 2/3
1/29/23, 6:08 PM IT_154_AIES_1

In [16]:
arr1 = np.array([1, 2, 3])

arr2 = np.array([4, 5, 6])

arr = np.concatenate((arr1, arr2))

print(arr)

[1 2 3 4 5 6]

In [17]:
arr = np.array([1, 2, 3, 4, 5, 6])

newarr = np.array_split(arr, 3)

print(newarr)

[array([1, 2]), array([3, 4]), array([5, 6])]

In [18]:
x = np.where(arr == 4)
print(x)

(array([3], dtype=int64),)

In [19]:
arr = np.array([3, 2, 0, 1])

print(np.sort(arr))

[0 1 2 3]

In [20]:
arr = np.array([41, 42, 43, 44])

x = [True, False, True, False]

newarr = arr[x]

print(newarr)

[41 43]

In [ ]:

In [ ]:

localhost:8890/nbconvert/html/IT_154_AIES_1.ipynb?download=false 3/3
2K20/IT/154
Assignment 2

1. Write down two intelligent programs for the TIC-TAC-TOE problem.

Artificial intelligence (or AI) is a computer program that can intelligently respond to the player’s moves.
This game doesn’t introduce any complicated new concepts. The artificial intelligence that plays Tic Tac
Toe is really just a few lines of code.

Two people play Tic Tac Toe with paper and pencil. One player is X and the other player is O. Players
take turns placing their X or O. If a player gets three of their marks on the board in a row, column, or one
of the two diagonals, they win. The game ends in a draw when the board fills up with neither player
winning.

The game is automatically played by the program and hence, no user input is needed. Still, developing an
automatic game will be lots of fun. Let’s see how to do this. NumPy and random Python libraries are used
to build this game. Instead of asking the user to put a mark on the board, the code randomly chooses a
place on the board and puts the mark. It will display the board after each turn unless a player wins. If the
game gets drawn, then it returns -1.

play_game() is the main function, which performs following tasks :


● Calls create_board() to create a 9×9 board and initializes with 0.
● For each player (1 or 2), calls the random_place() function to randomly choose a
● location on board and mark that location with the player number, alternatively.
● Print the board after each move.
● Evaluate the board after each move to check whether a row or column or
● diagonal has the same player number. If so, it displays the winner’s name. If after
● 9 moves, there are no winners then displays -1.
1/29/23, 6:08 PM IT_154_AIES_2

In [1]:
import numpy as np
import random
from time import sleep

In [2]:
def create_board():
return(np.array([[0, 0, 0],[0, 0, 0],[0, 0, 0]]))

In [3]:
def possibilities(board):
l = []

for i in range(len(board)):
for j in range(len(board)):

if board[i][j] == 0:
l.append((i, j))

return(l)

In [4]:
def random_place(board, player):
selection = possibilities(board)
current_loc = random.choice(selection)
board[current_loc] = player
return(board)

In [5]:
def row_win(board, player):
for x in range(len(board)):
win = True

for y in range(len(board)):
if board[x, y] != player:
win = False
continue

if win == True:
return(win)

return(win)

In [6]:
def col_win(board, player):
for x in range(len(board)):
win = True

for y in range(len(board)):
if board[y][x] != player:
win = False
continue

if win == True:
return(win)

localhost:8890/nbconvert/html/IT_154_AIES_2.ipynb?download=false 1/3
1/29/23, 6:08 PM IT_154_AIES_2

In [7]:
def diag_win(board, player):
win = True
y = 0
for x in range(len(board)):

if board[x, x] != player:
win = False

if win:
return win
win = True
if win:
for x in range(len(board)):
y = len(board) - 1 - x
if board[x, y] != player:
win = False

return win

In [8]:
def evaluate(board):
winner = 0

for player in [1, 2]:


if (row_win(board, player) or
col_win(board,player) or
diag_win(board,player)):

winner = player

if np.all(board != 0) and winner == 0:


winner = -1
return winner

In [9]:
def play_game():

board, winner, counter = create_board(), 0, 1


print(board)
sleep(2)

while winner == 0:
for player in [1, 2]:
board = random_place(board, player)
print("Board After" + str(counter) + "move")
print(board)
sleep(2)
counter += 1
winner = evaluate(board)
if winner != 0:
break

return(winner)

In [10]:
print("Winner is:" + str(play_game()))

localhost:8890/nbconvert/html/IT_154_AIES_2.ipynb?download=false 2/3
1/29/23, 6:08 PM IT_154_AIES_2

[[0 0 0]
[0 0 0]
[0 0 0]]
Board After1move
[[0 0 0]
[0 1 0]
[0 0 0]]
Board After2move
[[0 0 0]
[2 1 0]
[0 0 0]]
Board After3move
[[0 0 0]
[2 1 0]
[1 0 0]]
Board After4move
[[0 0 0]
[2 1 2]
[1 0 0]]
Board After5move
[[1 0 0]
[2 1 2]
[1 0 0]]
Board After6move
[[1 0 2]
[2 1 2]
[1 0 0]]
Board After7move
[[1 0 2]
[2 1 2]
[1 0 1]]
Winner is:1

In [ ]:

localhost:8890/nbconvert/html/IT_154_AIES_2.ipynb?download=false 3/3
2. Write down a program to implement Breadth-first search and depth-first search for the
water jug problem.

You are given an m litter jug and a n litter jug. Both the jugs are initially empty. The jugs don’t have
markings to allow measuring smaller quantities. You have to use the jugs to measure liters of water where
d is less than n. (X, Y) corresponds to a state where X refers to the amount of water in Jug1 and Y
refers to the amount of water in Jug2 Determine the path from the initial state (xi, yi) to the final state (xf,
yf), where (xi, yi) is (0, 0) which indicates both Jugs are initially empty and (xf, yf) indicates
a state which could be (0, d) or (d, 0).

The operations you can perform are:


1. Empty a Jug, (X, Y)-&gt;(0, Y) Empty Jug 1
2. Fill a Jug, (0, 0)-&gt;(X, 0) Fill Jug 1
3. Pour water from one jug to the other until one of the jugs is either empty or full

Examples:
Input : 4 3 2
Output : {(0, 0), (0, 3), (3, 0), (3, 3), (4, 2), (0, 2)}

As provided in the problem statement, at any given state we can do either of the following operations:
1. Fill a jug
2. Empty a jug
3. Transfer water from one jug to another until either of them gets completely filled or empty

Code:

from collections import deque def


bfs(start, end, q, visited):
if start == end:
return
for state in q: a,
b = state
for fill_a in [a, a - 4, a - 3, a + 3, a + 4]: for
fill_b in [b, b - 4, b - 3, b + 3, b + 4]:
if fill_a in [0, 3, 4] and fill_b in [0, 3, 4] and (fill_a, fill_b) not in visited:
visited.add((fill_a, fill_b))
q.append((fill_a, fill_b))
def main(): start
= (0, 0)
end = (2, 0)
q = deque([start]) visited
= set([start]) bfs(start, end,
q, visited) print(visited)
if name == ' main ':
main(

Output:

{(0, 0), (0, 3), (3, 0), (3, 3), (2, 2), (2, 0), (4, 0), (4, 4)}
2K20/IT/154
Assignment 3

1. Implement Best first search and least cost search for 8-Puzzle problem.

Bfs

from queue import PriorityQueue


# Helper function to get the index of the blank tile (0)
def get_blank_tile_index(state):
return state.index(0)
# Helper function to get the possible moves from the current state
def get_possible_moves(state):
blank_tile_index = get_blank_tile_index(state)
possible_moves = []
if blank_tile_index > 2: # move up
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-3] =
new_state[blank_tile_index-3], new_state[blank_tile_index]
possible_moves.append(new_state)
if blank_tile_index < 6: # move down
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+3] =
new_state[blank_tile_index+3], new_state[blank_tile_index]
possible_moves.append(new_state)
if blank_tile_index % 3 != 0: # move left
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-1] =
new_state[blank_tile_index-1], new_state [blank_tile_index]
possible_moves.append(new_state)
if blank_tile_index % 3 != 2: # move right
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+1] =
new_state[blank_tile_index+1], new_state[blank_tile_index]
possible_moves.append(new_state)
return possible_moves
# Heuristic function for Best-First Search (Number of misplaced tiles)
def misplaced_tiles(state):
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
return sum(s != g for (s, g) in zip(state, goal_state))
# Best-First Search algorithm
def best_first_search(initial_state):
frontier = PriorityQueue()
frontier.put((misplaced_tiles(initial_state), initial_state))
explored = set()
while not frontier.empty():
(h, current_state) = frontier.get()
explored.add(tuple(current_state))
if current_state == [1, 2, 3, 4, 5, 6, 7, 8, 0]: # goal state
return current_state
for next_state in get_possible_moves(current_state):
if tuple(next_state) not in explored:
frontier.put((misplaced_tiles(next_state), next_state))
return None
# Driver code to solve the 8-Puzzle problem using Best-First Search
initial_state = [1, 2, 3, 4, 0, 5, 7, 8, 6] # initial state
solution = best_first_search(initial_state)
if solution:
print("Solution found:", solution)
else:
print("Solution not found.")

Output

Least cost search

from queue import PriorityQueue


def get_blank_tile_index(state):
return state.index(0)
# Helper function to get the possible moves from the current state
def get_possible_moves(state):
blank_tile_index = get_blank_tile_index(state)
possible_moves = []
if blank_tile_index > 2: # move up
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-3] =
new_state[blank_tile_index-3], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index < 6: # move down
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+3] =
new_state[blank_tile_index+3], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index % 3 != 0: # move left
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-1] =
new_state[blank_tile_index-1], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index % 3 != 2: # move right
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+1] =
new_state[blank_tile_index+1], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
return possible_moves
# Heuristic function for Least Cost Search (Manhattan distance)
def manhattan_distance(state):
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
distance = 0
for i in range(3):
for j in range(3):
tile = state[3*i+j]
if tile != 0:
goal_pos = goal_state.index(tile)
distance += abs(i - goal_pos//3) + abs(j - goal_pos%3)
return distance
# Least Cost Search algorithm
def least_cost_search(initial_state):
frontier = PriorityQueue()
frontier.put((0, initial_state))
explored = set()
while not frontier.empty():
(cost, current_state) = frontier.get()
explored.add(tuple(current_state))
if current_state == [1, 2, 3, 4, 5, 6, 7, 8, 0]: # goal state
return current_state
for (next_state, step_cost) in get_possible_moves(current_state):
if tuple(next_state) not in explored:
frontier.put((cost + step_cost + manhattan_distance(next_state), next_state))
return None
initial_state = [1, 2, 3, 4, 0, 5, 7, 8, 6] # initial state
solution = least_cost_search(initial_state)
if solution:
print("Solution found:", solution)
else:
print("Solution not found.")
Output

2. Implement the steps of A* Algorithms for 8-Puzzle problem.

from queue import PriorityQueue


def get_blank_tile_index(state):
return state.index(0)
def get_possible_moves(state):
blank_tile_index = get_blank_tile_index(state)
possible_moves = []
if blank_tile_index > 2: # move up
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-3] =
new_state[blank_tile_index-3], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index < 6: # move down
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+3] =
new_state[blank_tile_index+3], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index % 3 != 0: # move left
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index-1] =
new_state[blank_tile_index-1], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
if blank_tile_index % 3 != 2: # move right
new_state = state[:]
new_state[blank_tile_index], new_state[blank_tile_index+1] =
new_state[blank_tile_index+1], new_state[blank_tile_index]
possible_moves.append((new_state, 1))
return possible_moves
def manhattan_distance(state):
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
distance = 0
for i in range(3):
for j in range(3):
tile = state[3*i+j]
if tile != 0:
goal_pos = goal_state.index(tile)
distance += abs(i - goal_pos//3) + abs(j - goal_pos%3)
return distance
def astar_search(initial_state):
frontier = PriorityQueue()
frontier.put((manhattan_distance(initial_state), 0, initial_state))
explored = set()
while not frontier.empty():
(_, cost, current_state) = frontier.get()
explored.add(tuple(current_state))
if current_state == [1, 2, 3, 4, 5, 6, 7, 8, 0]: # goal state
return current_state
for (next_state, step_cost) in get_possible_moves(current_state):
if tuple(next_state) not in explored:
frontier.put((cost + step_cost + manhattan_distance(next_state), cost +
step_cost, next_state))
return None
# Driver code to solve the 8-Puzzle problem using A*
initial_state = [1, 2, 3, 4, 0, 5, 7, 8, 6] # initial state
solution = astar_search(initial_state)
if solution:
print("Solution found:", solution)
else:
print("Solution not found.")

Output
AI Assignment 4/5
2K20/IT/154

● Experiment 4: Write a program to implement the DFS(depth-first search) algorithm in


python.

Depth first Search or Depth first traversal is a recursive algorithm for searching all the vertices of a graph
or tree data structure. Traversal means visiting all the nodes of a graph.A standard DFS implementation
puts each vertex of the graph into one of two categories:
● Visited
● Not Visited
The purpose of the algorithm is to mark each vertex as visited while avoiding cycles.The DFS algorithm
works as follows:
1. Start by putting any one of the graph's vertices on top of a stack.
2. Take the top item of the stack and add it to the visited list.
3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the visited list to the top
of the stack.
4. Keep repeating steps 2 and 3 until the stack is empty.

DFS implementation in python:

graph = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}

visited = set()

def dfs(visited, graph, node):


if node not in visited:
print (node)
visited.add(node)
for neighbor in graph[node]:
dfs(visited, graph, neighbor)

print("Following is the Depth-First Search")


dfs(visited, graph, '5')
In the above code, first, we will create the graph for which we will use the depth-first search. After
creation, we will create a set for storing the value of the visited nodes to keep track of the visited nodes of
the graph. After the above process, we will declare a function with the parameters as visited nodes, the
graph itself and the node respectively. And inside the function, we will check whether any node of the
graph is visited or not using the “if” condition. If not, then we will print the node and add it to the visited
set of nodes.Then we will go to the neighboring node of the graph and again call the DFS function to use
the neighbor parameter. At last, we will run the driver code which prints the final result of DFS by calling
the DFS the first time with the starting vertex of the graph.

Output
● Experiment 5: Implement the hill climbing algorithm in python

The hill-climbing algorithm is a local search algorithm used in mathematical optimization. An important
property of local search algorithms is that the path to the goal does not matter, only the goal itself matters.
Because of this, we do not need to worry about which path we took in order to reach a certain goal state,
all that matters is that we reached it.

The basic principle behind the algorithm is moving across neighboring states according to elevation or
increase in value. This working principle also causes the algorithm to be susceptible to local maximums.

Solving the traveling salesman problem using the hill climbing algorithm in python

In the Travelling salesman problem, we have a salesman who needs to visit a number of cities exactly
once, after which he returns to the first city. The distances between each pair of cities are known, and we
need to find the shortest route. As you can imagine, there is (often) a large number of possible solutions
(routes) to a specific Travelling salesman problem; the goal is to find the best (i.e. the shortest) solution.

Hill climbing tries to find the best solution to this problem by starting out with a random solution, and
then generate neighbors: solutions that only slightly differ from the current one. If the best of those
neighbors is better (i.e. shorter) than the current one, it replaces the current solution with this better
solution. It then repeats the pattern by again creating neighbors. If at some point no neighbor is better than
the current solution, it returns the then current solution. That’s it! The algorithm is quite simple, but it
needs to be said that it doesn’t always find the best solution. It can get stuck in a local maximum: a place
where the current solution isn’t the best solution to the problem, but where none of the direct neighbors of
the current solution are better than the current solution. As described, the algorithm will stop at such a
point, unfortunately without returning the best solution. More complicated algorithms exist that have a
higher chance of finding the best solution, but they often take more computational resources

Code

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):
routeLength = 0
for i in range(len(solution)):
routeLength += tsp[solution[i - 1]][solution[i]]
return routeLength

def getNeighbours(solution):
neighbours = []
for i in range(len(solution)):
for j in range(i + 1, len(solution)):
neighbour = solution.copy()
neighbour[i] = solution[j]
neighbour[j] = solution[i]
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)
neighbours = getNeighbours(currentSolution)
bestNeighbour, bestNeighbourRouteLength = getBestNeighbour(tsp, neighbours)

while bestNeighbourRouteLength < currentRouteLength:


currentSolution = bestNeighbour
currentRouteLength = bestNeighbourRouteLength
neighbours = getNeighbours(currentSolution)
bestNeighbour, bestNeighbourRouteLength = getBestNeighbour(tsp, neighbours)

return currentSolution, currentRouteLength

def main():
tsp = [
[0, 400, 500, 300],
[400, 0, 300, 500],
[500, 300, 0, 400],
[300, 500, 400, 0]
]

print(hillClimbing(tsp))

if __name__ == "__main__":
main()

main()

Output
2K20/IT/154
Assignment 6

Write a program to implement a neural network in Python.

Code:
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
# Define the training data
X_train = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_train = np.array([0, 1, 1, 0])
# Define the neural network architecture
model = Sequential()
model.add(Dense(units=2, input_dim=2, activation='relu'))
model.add(Dense(units=1, activation='sigmoid'))
# Compile the model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Train the model
model.fit(X_train, y_train, epochs=1000)
# Test the model
X_test = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_test = np.array([0, 1, 1, 0])
_, accuracy = model.evaluate(X_test, y_test)
print("Accuracy: %.2f%%" % (accuracy * 100))

Output:
AI Assignment 7
2K20/IT/154

● Experiment 7: Compare the different search algorithms.

Numerous search algorithms are available, each with unique strengths and limitations. Here is a
comparison of some of the commonly used search algorithms:

Linear Search:
This algorithm examines every element in a list or array until it discovers the target value. Although it is
simple to implement and performs well on small datasets, it can be sluggish on larger datasets due to the
need to scan every element. Its time complexity is O(n).

Binary Search:
This algorithm is more efficient and is used on sorted lists. It begins by examining the middle element,
and if the target value is less than the middle element, it searches the left half of the list; otherwise, it
searches the right half. This procedure is repeated until the target value is discovered or the list is
exhausted. Binary search has a time complexity of O(log n), making it faster than linear search on larger
datasets.

Depth-First Search (DFS):


This graph traversal algorithm begins at a root node and investigates as far as feasible along each branch
before backtracking. It is frequently used to solve problems such as finding paths or cycles in a graph.
DFS has a time complexity of O(V + E), where V is the number of vertices and E is the number of edges.

Breadth-First Search (BFS):


This graph traversal algorithm explores all the vertices at the same level before moving on to the next
level. It is frequently used to locate the shortest path between two vertices or to solve problems that
require finding the closest neighbor. BFS has a time complexity of O(V + E), comparable to DFS.

A* Search:
This heuristic search algorithm employs an estimate of the distance to the goal to guide its search. It
combines the efficiency of greedy best-first search with the completeness of uniform-cost search. A* is
frequently used in pathfinding problems, such as finding the shortest route between two points on a map.
Its time complexity is determined by the heuristic function used, but generally, it is O(b^d), where b is the
branching factor and d is the depth of the solution.

Dijkstra's Algorithm:
This greedy algorithm finds the shortest path between two vertices in a graph with non-negative weights.
It begins at the source vertex and iteratively adds the closest unvisited vertex to the shortest path tree.
Dijkstra's algorithm has a time complexity of O(V^2), but with the use of a priority queue, it can be
reduced to O(E + V log V), where E is the number of edges and V is the number of vertices.
Overall, the selection of a search algorithm is determined by the specific problem and the data
characteristics. Some algorithms work better on smaller datasets, while others scale more effectively on
larger datasets. The existence or lack of a sorted order, the data structure (graphs or arrays), and the need
for heuristic information are also crucial factors to consider when selecting a search algorithm.
● Experiment 8:

Prolog program to compute factorial of a number

For positive factorial

fact(0,1).
fact(N,F):-
(

N>0 ->
(
N1 is N-1,
fact(N1,F1),
F is N*F1
)
;

For negative factorial

N<0 ->
(
N1 is N+1,
fact(N1,F1),
F is N*F1
)
).

Output:
Fibonacci number prolog program

fib(0, 1) :- !.
fib(1, 1) :- !.
fib(N, F) :-
N > 1,
N1 is N-1,
N2 is N-2,
fib(N1, F1),
fib(N2, F2),
F is F1+F2.

Output:

Compute area and circumference of a circle

area(R,A):- Pi is 3.14, A is (Pi*R*R),


write(“area of a circle is: “),write(A).

Output:
2K20/IT/154
Assignment 9

Write a program to solve the 4-Queen problem in PROLOG.

Code

queens(N, Queens) :-
length(Queens, N),
board(Queens, Board, 0, N, _, _),
queens(Board, 0, Queens).
board([], [], N, N, _, _).
board([_|Queens], [Col-Vars|Board], Col0, N, [_|VR], VC) :-
Col is Col0+1,
functor(Vars, f, N),
constraints(N, Vars, VR, VC),
board(Queens, Board, Col, N, VR, [_|VC]).
constraints(0, _, _, _) :- !.
constraints(N, Row, [R|Rs], [C|Cs]) :-
arg(N, Row, R-C),
M is N-1,
constraints(M, Row, Rs, Cs).
queens([], _, []).
queens([C|Cs], Row0, [Col|Solution]) :-
Row is Row0+1,
select(Col-Vars, [C|Cs], Board),
arg(Row, Vars, Row-Row),
queens(Board, Row, Solution).
?- queens(4, Queens).

Output

You might also like