Sei sulla pagina 1di 44

NITTE MEENAKSHI INSTITUTE OF TECHNOLOGY

(AN AUTONOMOUS INSTITUTION AFFILIATED TO VISVESVARAYA TECHNOLOGICAL UNIVERSITY, BELGAUM)


PB No. 6429, Yelahanka, Bangalore 560-064, Karnataka
Telephone: 080- 22167800, 22167860

ARTIFICIAL INTELLEGENCE
ASSIGNMENT

Submitted by:

SUSHRUTH (1NT17CS194)
TEJAS KRISHNA (1NT17CS197)

VARUN G (1NT17CS202)

DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

1|Page
ACKNOWLEDGEMENT

The satisfaction and euphoria that accompany the successful completion of any
task would be incomplete without the mention of the people who made it
possible, whose constant guidance and encouragement crowned our effort with
success. I express my sincere gratitude to our Principal Dr H. C. Nagaraj, Nitte
Meenakshi Institute of Technology for providing facilities.

We wish to thank our HOD, Dr Thippeswamy M.N. for the excellent


environment created for further educational growth in our department. We also
thank him for the invaluable guidance provided which has helped in the creation
of a better project.

I hereby like to thank our guide Shilpa Shree, Assistant Professor, Department of
Computer Science & Engineering on her periodic inspection, time to time evaluation
of the project and help to bring the project to the present form.

2|Page
DECLARATION
I hereby declare that,

(i) This report does not contain text, graphics or tables copied and pasted
from the Internet, unless specifically acknowledged, and the source being
detailed in the report and in the References sections.
(ii) All corrections and suggestions indicated during the internal
presentation have been incorporated in the report.

SL.NO NAME SIGNATURE

1 SUSHRUTH

2 TEJAS KRISHNA

3 VARUN G

3|Page
Table of Contents

Sl. No CONTENTS

1. Introduction of uninformed and informed search

2.
Breadth First Search
3. Depth First Search

4. Uniform Cost Search

5. Greedy Best First Search

6. A* Search Algorithm

7. Depth Limited Search

8. Iterative Depth First Search

9. Conclusion

4|Page
Introduction to Informed search
The informed search technique utilizes the problem specific knowledge in order
to give a clue to the solution of the problem. This type of search strategy
actually prevents the algorithms from stumbling about the goal and the direction
to the solution. Informed search can be advantageous in terms of the cost where
the optimality is achieved at lower search costs.

To search an optimal path cost in a graph by implementing informed search


strategy the most promising nodes n are inserted to the heuristic function h(n).
Then the function returns a non-negative real number which is an approximate
path cost calculated from node n to the target node.

Here the most important part of the informed technique is the heuristic function
which facilitates in imparting the additional knowledge of the problem to the
algorithm. As a result, it helps in finding the way to the goal through the various
neighbouring nodes. There are various algorithms based on the informed search
such as heuristic depth-first search, heuristic breadth-first search, A*search,
etcetera. Let’s now understand heuristic depth-first search.

5|Page
Introduction to Uninformed search
The uninformed search is different from informed search in the way that it just
provides the problem definition but no further step to finding the solution to the
problem. The primary objective of uninformed search is to differentiate between
the target and non-target state, and it totally ignores the destination it is heading
towards in the path until it discovers the goal and reports successor. This
strategy is also known as a blind search.

There are various search algorithms under this category such as depth-first
search, uniform cost search, breadth-first search, and so on. Let us now
understand the concept behind the uninformed search with the help of depth-
first search.

6|Page
Depth First Search

Algorithm:

DFS-iterative (G, s): //Where G is graph and s is source vertex


let S be stack
S.push( s ) //Inserting s in stack
mark s as visited.
while ( S is not empty):
//Pop a vertex from stack to visit next
v = S.top( )
S.pop( )
//Push all the neighbours of v in stack that are not visited
for all neighbours w of v in Graph G:
if w is not visited :
S.push( w )
mark w as visited
DFS-recursive(G, s):
mark s as visited
for all neighbours w of s in Graph G:
if w is not visited:
DFS-recursive(G, w)

7|Page
Program code:

# Python program to print DFS traversal from a


# given 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[v]= True
print v,

# Recur for all the vertices adjacent to this vertex


for i in self.graph[v]:
if visited[i] == False:
self.DFSUtil(i, visited)

# The function to do DFS traversal. It uses


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

# Mark all the vertices as not visited


visited = [False]*(len(self.graph))

8|Page
# Call the recursive helper function to print
# DFS traversal
self.DFSUtil(v,visited)

# Driver code
# 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 DFS from (starting from vertex 2)"


g.DFS(2)

9|Page
Output and Analysis:

Following is Depth First Traversal (starting from vertex 2)


2013

Time Complexity: O(V+E) where V is number of vertices in the graph and E is


number of edges in the graph.

10 | P a g e
Breadth First Search

Algorithm:

BFS (G, s) //Where G is the graph and s is


the source node
let Q be queue.
Q.enqueue( s ) //Inserting s in queue until all its neighbour vertices
are marked.
mark s as visited.
while ( Q is not empty)
//Removing that vertex from queue,whose neighbour will be
visited now
v = Q.dequeue( )

//processing all the neighbours of v


for all neighbours w of v in Graph G
if w is not visited Q.enqueue( w ) //Stores w in Q to
further visit its neighbour
mark w as visited.

11 | P a g e
Program code:

# Python3 Program to print BFS traversal


# from a given source vertex. BFS(int s)
# traverses vertices reachable from s.
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] * (len(self.graph))

# 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
12 | P a g e
s = queue.pop(0)
print (s, end = " ")

# Get all adjacent vertices of the


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

# Driver code

# 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)

13 | P a g e
Output and Analysis:

Following is Breadth First Traversal (starting from vertex 2)


2031

14 | P a g e
Uniformed Cost Search

Algorithm:

15 | P a g e
Program code:

// C++ implemenatation of above approach


#include <bits/stdc++.h>
using namespace std;

// graph
vector<vector<int> > graph;

// map to store cost of edges


map<pair<int, int>, int> cost;

// returns the minimum cost in a vector( if


// there are multiple goal states)
vector<int> uniform_cost_search(vector<int> goal, int start)
{
// minimum cost upto
// goal state from starting
// state
vector<int> answer;

// create a priority queue


priority_queue<pair<int, int> > queue;

// set the answer vector to max value


for (int i = 0; i < goal.size(); i++)
answer.push_back(INT_MAX);

// insert the starting index


queue.push(make_pair(0, start));

// map to store visited node


map<int, int> visited;

// count
int count = 0;

// while the queue is not empty


while (queue.size() > 0) {

// get the top element of the


// priority queue
pair<int, int> p = queue.top();

// pop the element


queue.pop();
16 | P a g e
// get the original value
p.first *= -1;

// check if the element is part of


// the goal list
if (find(goal.begin(), goal.end(), p.second) != goal.end()) {

// get the position


int index = find(goal.begin(), goal.end(),
p.second) - goal.begin();

// if a new goal is reached


if (answer[index] == INT_MAX)
count++;

// if the cost is less


if (answer[index] > p.first)
answer[index] = p.first;

// pop the element


queue.pop();

// if all goals are reached


if (count == goal.size())
return answer;
}

// check for the non visited nodes


// which are adjacent to present node
if (visited[p.second] == 0)
for (int i = 0; i < graph[p.second].size(); i++) {

// value is multiplied by -1 so that


// least priority is at the top
queue.push(make_pair((p.first +
cost[make_pair(p.second, graph[p.second][i])]) * -1,
graph[p.second][i]));
}

// mark as visited
visited[p.second] = 1;
}

return answer;
}
17 | P a g e
// main function
int main()
{
// create the graph
graph.resize(7);

// add edge
graph[0].push_back(1);
graph[0].push_back(3);
graph[3].push_back(1);
graph[3].push_back(6);
graph[3].push_back(4);
graph[1].push_back(6);
graph[4].push_back(2);
graph[4].push_back(5);
graph[2].push_back(1);
graph[5].push_back(2);
graph[5].push_back(6);
graph[6].push_back(4);

// add the cost


cost[make_pair(0, 1)] = 2;
cost[make_pair(0, 3)] = 5;
cost[make_pair(1, 6)] = 1;
cost[make_pair(3, 1)] = 5;
cost[make_pair(3, 6)] = 6;
cost[make_pair(3, 4)] = 2;
cost[make_pair(2, 1)] = 4;
cost[make_pair(4, 2)] = 4;
cost[make_pair(4, 5)] = 3;
cost[make_pair(5, 2)] = 6;
cost[make_pair(5, 6)] = 3;
cost[make_pair(6, 4)] = 7;

// goal state
vector<int> goal;

// set the goal


// there can be multiple goal states
goal.push_back(6);

// get the answer


vector<int> answer = uniform_cost_search(goal, 0);

// print the answer


18 | P a g e
cout << "Minimum cost from 0 to 6 is = "
<< answer[0] << endl;

return 0;
}

19 | P a g e
Output and Analysis:

Minimum cost from 0 to 6 is = 3

Complexity: O( m ^ (1+floor(l/e)))
where,
m is the maximum number of neighbor a node has
l is the length of the shortest path to the goal state
e is the least cost of an edge

20 | P a g e
Greedy Best First Search

Algorithm:

Best-First-Search(Grah g, Node start)


1) Create an empty PriorityQueue
PriorityQueue pq;
2) Insert "start" in pq.
pq.insert(start)
3) Until PriorityQueue is empty
u = PriorityQueue.DeleteMin
If u is the goal
Exit
Else
Foreach neighbor v of u
If v "Unvisited"
Mark v "Visited"
pq.insert(v)
Mark u "Examined"
End procedure

21 | P a g e
Program code:

import networkx as nx

import matplotlib.pyplot as plt

import Queue as Q

def getPriorityQueue(list):

q = Q.PriorityQueue()

for node in list:

q.put(Ordered_Node(heuristics[node],node))

return q,len(list)

def greedyBFSUtil(G, v, visited, final_path, dest, goal):

if goal == 1:

return goal

visited[v] = True

final_path.append(v)

if v == dest:

goal = 1

else:

pq_list = []

pq,size = getPriorityQueue(G[v])

for i in range(size):

pq_list.append(pq.get().description)

for i in pq_list:

if goal != 1:
22 | P a g e
#print "current city:", i

if visited[i] == False :

goal = greedyBFSUtil(G, i, visited, final_path,


dest, goal)

return goal

def greedyBFS(G, source, dest, heuristics, pos):

visited = {}

for node in G.nodes():

visited[node] = False

final_path = []

goal = greedyBFSUtil(G, source, visited, final_path, dest, 0)

prev = -1

for var in final_path:

if prev != -1:

curr = var

nx.draw_networkx_edges(G, pos, edgelist = [(prev,curr)],


width = 2.5, alpha = 0.8, edge_color = 'black')

prev = curr

else:

prev = var

return

23 | P a g e
class Ordered_Node(object):

def __init__(self, priority, description):

self.priority = priority

self.description = description

return

def __cmp__(self, other):

return cmp(self.priority, other.priority)

def getHeuristics(G):

heuristics = {}

f = open('heuristics.txt')

for i in G.nodes():

node_heuristic_val = f.readline().split()

heuristics[node_heuristic_val[0]] = node_heuristic_val[1]

return heuristics

#takes input from the file and creates a weighted graph

def CreateGraph():

G = nx.Graph()

f = open('input.txt')

n = int(f.readline())

for i in range(n):

graph_edge_list = f.readline().split()

24 | P a g e
G.add_edge(graph_edge_list[0], graph_edge_list[1], length =
graph_edge_list[2])

source, dest= f.read().splitlines()

return G, source, dest

def DrawPath(G, source, dest):

pos = nx.spring_layout(G)

val_map = {}

val_map[source] = 'green'

val_map[dest] = 'red'

values = [val_map.get(node, 'blue') for node in G.nodes()]

nx.draw(G, pos, with_labels = True, node_color = values, edge_color =


'b' ,width = 1, alpha = 0.7) #with_labels=true is to show the node number in the
output graph

edge_labels = dict([((u, v,), d['length']) for u, v, d in G.edges(data =


True)])

nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels,


label_pos = 0.5, font_size = 11) #prints weight on all the edges

return pos

#main function

if __name__ == "__main__":

G, source,dest = CreateGraph()

heuristics = getHeuristics(G)

pos = DrawPath(G, source, dest)

greedyBFS(G, source, dest, heuristics, pos)

plt.show()

25 | P a g e
Output and Analysis:

 The worst case time complexity for Best First Search is O(n * Log n) where n is
number of nodes. In worst case, we may have to visit all nodes before we reach
goal. Note that priority queue is implemented using Min(or Max) Heap, and insert
and remove operations take O(log n) time.
 Performance of the algorithm depends on how well the cost or evaluation function
is designed.

26 | P a g e
A* Search

Algorithm:

1. Initialize the open list


2. Initialize the closed list
put the starting node on the open
list (you can leave its f at zero)

3. while the open list is not empty


a) find the node with the least f on
the open list, call it "q"

b) pop q off the open list

c) generate q's 8 successors and set their


parents to q

d) for each successor


i) if successor is the goal, stop search
successor.g = q.g + distance between
successor and q
successor.h = distance from goal to
successor (This can be done using many
ways, we will discuss three heuristics-
Manhattan, Diagonal and Euclidean
Heuristics)

successor.f = successor.g + successor.h

ii) if a node with the same position as


successor is in the OPEN list which has a
lower f than successor, skip this successor

iii) if a node with the same position as


successor is in the CLOSED list which has
a lower f than successor, skip this successor
otherwise, add the node to the open list
end (for loop)

e) push q on the closed list


end (while loop)

27 | P a g e
Program code:

import java.util.*;

public abstract class AStar<T>{

private class Path implements Comparable{

public T point;
public Double f;
public Double g;
public Path parent;

/**
* Default c'tor.
*/
public Path(){
parent = null;
point = null;
g = f = 0.0;
}

/**
* C'tor by copy another object.
*
* @param p The path object to clone.
*/
public Path(Path p){
this();
parent = p;
g = p.g;
f = p.f;
}

/**
* Compare to another object using the total cost f.
*
* @param o The object to compare to.
* @see Comparable#compareTo()
* @return <code>less than 0</code> This object is smaller
28 | P a g e
* than <code>0</code>;
* <code>0</code> Object are the same.
* <code>bigger than 0</code> This object is bigger
* than o.
*/
public int compareTo(Object o){
Path p = (Path)o;
return (int)(f - p.f);
}

/**
* Get the last point on the path.
*
* @return The last point visited by the path.
*/
public T getPoint(){
return point;
}

/**
* Set the
*/
public void setPoint(T p){
point = p;
}
}

/**
* Check if the current node is a goal for the problem.
*
* @param node The node to check.
* @return <code>true</code> if it is a goal, <code>false</else>
otherwise.
*/
protected abstract boolean isGoal(T node);

/**
* Cost for the operation to go to <code>to</code> from
* <code>from</from>.
*
29 | P a g e
* @param from The node we are leaving.
* @param to The node we are reaching.
* @return The cost of the operation.
*/
protected abstract Double g(T from, T to);

/**
* Estimated cost to reach a goal node.
* An admissible heuristic never gives a cost bigger than the real
* one.
* <code>from</from>.
*
* @param from The node we are leaving.
* @param to The node we are reaching.
* @return The estimated cost to reach an object.
*/
protected abstract Double h(T from, T to);

/**
* Generate the successors for a given node.
*
* @param node The node we want to expand.
* @return A list of possible next steps.
*/
protected abstract List<T> generateSuccessors(T node);

private PriorityQueue<Path> paths;


private HashMap<T, Double> mindists;
private Double lastCost;
private int expandedCounter;

/**
* Check how many times a node was expanded.
*
* @return A counter of how many times a node was expanded.
*/
public int getExpandedCounter(){
return expandedCounter;
}

30 | P a g e
/**
* Default c'tor.
*/
public AStar(){
paths = new PriorityQueue<Path>();
mindists = new HashMap<T, Double>();
expandedCounter = 0;
lastCost = 0.0;
}

/**
* Total cost function to reach the node <code>to</code> from
* <code>from</code>.
*
* The total cost is defined as: f(x) = g(x) + h(x).
* @param from The node we are leaving.
* @param to The node we are reaching.
* @return The total cost.
*/
protected Double f(Path p, T from, T to){
Double g = g(from, to) + ((p.parent != null) ? p.parent.g : 0.0);
Double h = h(from, to);

p.g = g;
p.f = g + h;

return p.f;
}

/**
* Expand a path.
*
* @param path The path to expand.
*/
private void expand(Path path){
T p = path.getPoint();
Double min = mindists.get(path.getPoint());

/*
* If a better path passing for this point already exists then
31 | P a g e
* don't expand it.
*/
if(min == null || min.doubleValue() > path.f.doubleValue())
mindists.put(path.getPoint(), path.f);
else
return;

List<T> successors = generateSuccessors(p);

for(T t : successors){
Path newPath = new Path(path);
newPath.setPoint(t);
f(newPath, path.getPoint(), t);
paths.offer(newPath);
}

expandedCounter++;
}

/**
* Get the cost to reach the last node in the path.
*
* @return The cost for the found path.
*/
public Double getCost(){
return lastCost;
}

/**
* Find the shortest path to a goal starting from
* <code>start</code>.
*
* @param start The initial node.
* @return A list of nodes from the initial point to a goal,
* <code>null</code> if a path doesn't exist.
*/
public List<T> compute(T start){
try{
Path root = new Path();
root.setPoint(start);
32 | P a g e
/* Needed if the initial point has a cost. */
f(root, start, start);

expand(root);

for(;;){
Path p = paths.poll();

if(p == null){
lastCost = Double.MAX_VALUE;
return null;
}

T last = p.getPoint();

lastCost = p.g;

if(isGoal(last)){
LinkedList<T> retPath = new
LinkedList<T>();

for(Path i = p; i != null; i =
i.parent){

retPath.addFirst(i.getPoint());
}

return retPath;
}
expand(p);
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
}

33 | P a g e
Output and Analysis:

34 | P a g e
Depth Limited Search

Algorithm:

35 | P a g e
Program code:

36 | P a g e
37 | P a g e
Output and Analysis:

38 | P a g e
Iterative deepening DFS

Algorithm:

// Returns true if target is reachable from


// src within max_depth
bool IDDFS(src, target, max_depth)
for limit from 0 to max_depth
if DLS(src, target, limit) == true
return true
return false

bool DLS(src, target, limit)


if (src == target)
return true;

// If reached the maximum depth,


// stop recursing.
if (limit <= 0)
return false;

foreach adjacent i of src


if DLS(i, target, limit?1)
return true

return false

39 | P a g e
Program code:

# Python program to print DFS traversal from a given


# given graph
from collections import defaultdict

# This class represents a directed graph using adjacency


# list representation
class Graph:

def __init__(self,vertices):

# No. of vertices
self.V = vertices

# 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 to perform a Depth-Limited search


# from given source 'src'
def DLS(self,src,target,maxDepth):

if src == target : return True

# If reached the maximum depth, stop recursing.


if maxDepth <= 0 : return False

# Recur for all the vertices adjacent to this vertex


for i in self.graph[src]:
if(self.DLS(i,target,maxDepth-1)):
return True
return False

# IDDFS to search if target is reachable from v.


# It uses recursive DLS()
def IDDFS(self,src, target, maxDepth):

# Repeatedly depth-limit search till the


# maximum depth
for i in range(maxDepth):
if (self.DLS(src, target, i)):
return True
40 | P a g e
return False

# Create a graph given in the above diagram


g = Graph (7);
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(2, 5)
g.addEdge(2, 6)

target = 6; maxDepth = 3; src = 0

if g.IDDFS(src, target, maxDepth) == True:


print ("Target is reachable from source " +
"within max depth")
else :
print ("Target is NOT reachable from source " +
"within max depth")

41 | P a g e
Output and Analysis:

Target is reachable from source within max depth

42 | P a g e
Conclusion

43 | P a g e
References
https://www.geeksforgeeks.org
https://www.hackerearth.com

44 | P a g e

Potrebbero piacerti anche