Search Algorithms in AI: BFS & DFS
Search Algorithms in AI: BFS & DFS
Searching for solutions, uniformed search strategies – Breadth first search, depth first Search.
Search with partial information (Heuristic search) Hill climbing, A* ,AO* Algorithms, Problem
reduction, Game Playing - Adversial search, Games, mini-max algorithm, optimal decisions in
multiplayer games, Problem in Game playing, Alpha-Beta pruning, Evaluation functions.
Search: Searching is a step by step procedure to solve a search-problem in a given search space.
A search problem can have three main factors:
a. Search Space: Search space represents a set of possible solutions, which a system
may have.
b. Start State: It is a state from where agent begins the search.
c. Goal test: It is a function which observe the current state and returns whether the
goal state is achieved or not.
Search tree: A tree representation of search problem is called Search tree. The root of the search
tree is the root node which is corresponding to the initial state.
Actions: It gives the description of all the available actions to the agent.
Transition model: A description of what each action do, can be represented as a transition
model.
Path Cost: It is a function which assigns a numeric cost to each path.
Solution: It is an action sequence which leads from the start node to the goal node.
Optimal Solution: If a solution has the lowest cost among all solutions.
Advantages:
o BFS will provide a solution if any solution exists.
o If there are more than one solutions for a given problem, then BFS will provide the
minimal solution which requires the least number of steps.
o It also helps in finding the shortest path in goal state, since it needs all nodes at the same
hierarchical level before making a move to nodes at lower levels.
o It is also very easy to comprehend with the help of this we can assign the higher rank
among path types.
Disadvantages:
o It requires lots of memory since each level of the tree must be saved into memory to
expand the next level.
o BFS needs lots of time if the solution is far away from the root node.
o It can be very inefficient approach for searching through deeply layered spaces, as it
needs to thoroughly explore all nodes at each level before moving on to the next
Example:
In the below tree structure, we have shown the traversing of the tree using BFS algorithm from
the root node S to goal node K. BFS search algorithm traverse in layers, so it will follow the path
which is shown by the dotted arrow, and the traversed path will be:
1. S---> A--->B---->C--->D---->G--->H--->E---->F---->I---->K
Time Complexity: Time Complexity of BFS algorithm can be obtained by the number of nodes
traversed in BFS until the shallowest Node. Where the d= depth of shallowest solution and b is a
node at every state.
T (b) = 1+b2+b3+.......+ bd= O (bd)
Space Complexity: Space complexity of BFS algorithm is given by the Memory size of frontier
which is O(bd).
Completeness: BFS is complete, which means if the shallowest goal node is at some finite
depth, then BFS will find a solution.
Optimality: BFS is optimal if path cost is a non-decreasing function of the depth of the node.
2. Depth-first Search
o Depth-first search isa recursive algorithm for traversing a tree or graph data structure.
o 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.
o DFS uses a stack data structure for its implementation.
o The process of the DFS algorithm is similar to the BFS algorithm.
Advantage:
o DFS requires very less memory as it only needs to store a stack of the nodes on the path
from root node to the current node.
o It takes less time to reach to the goal node than BFS algorithm (if it traverses in the right
path).
o With the help of this we can stores the route which is being tracked in memory to save
time as it only needs to keep one at a particular time.
Disadvantage:
o There is the possibility that many states keep re-occurring, and there is no guarantee of
finding the solution.
o DFS algorithm goes for deep down searching and sometime it may go to the infinite loop.
o The depth-first search (DFS) algorithm does not always find the shorte¬st path to a
solution.
Example:
In the below search tree, we have shown the flow of depth-first search, and it will follow the
order as:
Root node--->Left node ----> right node.
It will start searching from root node S, and traverse A, then B, then D and E, after traversing E,
it will backtrack the tree as E has no other successor and still goal node is not found. After
backtracking it will traverse node C and then G, and here it will terminate as it found goal node.
Completeness: DFS search algorithm is complete within finite state space as it will expand
every node within a limited search tree.
Time Complexity: Time complexity of DFS will be equivalent to the node traversed by the
algorithm. It is given by:
T(n)= 1+ n2+ n3 +.........+ nm=O(nm)
Where, m= maximum depth of any node and this can be much larger than d (Shallowest
solution depth)
Space Complexity: DFS algorithm needs to store only single path from the root node, hence
space complexity of DFS is equivalent to the size of the fringe set, which is O(bm).
Optimal: DFS search algorithm is non-optimal, as it may generate a large number of steps or
high cost to reach to the goal node.
These techniques are essential for tasks that involve finding the best path from a starting point
to a goal state, such as in navigation systems, game playing, and optimization problems. This
article delves into what heuristic search is, its significance, and the various techniques
employed in AI.
Understanding Heuristic Search
Heuristics operates on the search space of a problem to find the best or closest-to-optimal
solution via the use of systematic algorithms. In contrast to a brute-force approach, which
checks all possible solutions exhaustively, a heuristic search method uses heuristic information
to define a route that seems more plausible than the rest. Heuristics, in this case, refer to a set
of criteria or rules of thumb that offer an estimate of a firm’s profitability. Utilizing heuristic
guiding, the algorithms determine the balance between exploration and exploitation, and thus
they can successfully tackle demanding issues. Therefore, they enable an efficient solution
finding process.
Hill Climbing
Hill Climbing can be useful in a variety of optimization problems, such as scheduling, route
planning, and resource allocation. However, it has some limitations, such as the tendency to
get stuck in local maxima and the lack of diversity in the search space. Therefore, it is often
combined with other optimization techniques, such as genetic algorithms or simulated
annealing, to overcome these limitations and improve the search results.
A* search is the most commonly 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 solve 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 similar to UCS
except that it uses g(n)+h(n) instead of g(n).
In A* search algorithm, we use search heuristic as well as the cost to reach the node. Hence we
can combine both costs as following, and this sum is called as a fitness number.
Algorithm of A* search:
Step1: Place the starting node in the OPEN list.
Step 2: Check if the OPEN list is empty or not, if the list is empty then return failure and stops.
Step 3: Select the node from the OPEN list which has the smallest value of evaluation function
(g+h), if node n is goal node then return success and stop, otherwise
Step 4: Expand node n and generate all of its successors, and put n into the closed list. For each
successor n', check whether n' is already in the OPEN or CLOSED list, if not then compute
evaluation function for n' and place into Open list.
Step 5: Else if node n' is already in OPEN and CLOSED, then it should be attached to the back
pointer which reflects the lowest g(n') value.
Step 6: Return to Step 2.
Advantages:
o A* search algorithm is the best algorithm than other search algorithms.
o A* search algorithm is optimal and complete.
o This algorithm can solve very complex problems.
Disadvantages:
o It does not always produce the shortest path as it mostly based on heuristics and
approximation.
o A* search algorithm has some complexity issues.
o The main drawback of A* is memory requirement as it keeps all generated nodes in the
memory, so it is not practical for various large-scale problems.
Example:
In this example, we will traverse the given graph using the A* algorithm. The heuristic value of
all states is given in the below table so we will calculate the f(n) of each state using the formula
f(n)= g(n) + h(n), where g(n) is the cost to reach any node from start state.
In the above figure, the buying of a car may be broken down into smaller problems or tasks
that can be accomplished to achieve the main goal in the above figure, which is an example of
a simple AND-OR graph. The other task is to either steal a car that will help us accomplish the
main goal or use your own money to purchase a car that will accomplish the main goal. The
AND symbol is used to indicate the AND part of the graphs, which refers to the need that all
subproblems containing the AND to be resolved before the preceding node or issue may be
finished.
The start state and the target state are already known in the knowledge-based search strategy
known as the AO* algorithm, and the best path is identified by heuristics. The informed
search technique considerably reduces the algorithm’s time complexity. The AO* algorithm is
far more effective in searching AND-OR trees than the A* algorithm.
Here in the above example below the Node which is given is the heuristic value i.e h(n). Edge
length is considered as 1.
Step 1
Step 2
According to the answer of step 1, explore node B
Here the value of E & F are calculated as follows,
Step 3
f(C⇢H+I) is selected as the path with the lowest cost and the heuristic is also left unchanged
because it matches the actual cost. Paths H & I are solved because the heuristic for those paths
is 0,
but Path A⇢D needs to be calculated because it has an AND.
as we can see that path f(A⇢C+D) is get solved and this tree has become a solved tree now.
In simple words, the main flow of this algorithm is that we have to find firstly level 1st
heuristic
value and then level 2nd and after that update the values with going upward means towards
the root node.
In the above tree diagram, we have updated all the values.
PROBLEM REDUCTION
Problem reduction is a key method in artificial intelligence (AI) that helps solve complex issues.
It works by breaking down big problems into smaller, more manageable parts. This approach
makes it easier for AI systems to find solutions.
Example Explanation:
o From the initial state, MAX has 9 possible moves as he starts first. MAX place x and
MIN place o, and both player plays alternatively until we reach a leaf node where one
player has three in a row or all squares are filled.
o Both players will compute each node, minimax, the minimax value which is the best
achievable utility against an optimal adversary.
o Suppose both the players are well aware of the tic-tac-toe and playing the best play. Each
player is doing his best to prevent another one from winning. MIN is acting against Max
in the game.
o So in the game tree, we have a layer of Max, a layer of MIN, and each layer is called
as Ply. Max place x, then MIN puts o to prevent Max from winning, and this game
continues until the terminal node.
o In this either MIN wins, MAX wins, or it's a draw. This game-tree is the whole search
space of possibilities that MIN and MAX are playing tic-tac-toe and taking turns
alternately.
Mini-Max Algorithm
o Mini-max algorithm is a recursive or backtracking algorithm which is used in decision-
making and game theory. It provides an optimal move for the player assuming that
opponent is also playing optimally.
o Mini-Max algorithm uses recursion to search through the game-tree.
o Min-Max algorithm is mostly used for game playing in AI. Such as Chess, Checkers, tic-
tac-toe, go, and various tow-players game. This Algorithm computes the minimax
decision for the current state.
o In this algorithm two players play the game, one is called MAX and other is called MIN.
o Both the players fight it as the opponent player gets the minimum benefit while they get
the maximum benefit.
o Both Players of the game are opponent of each other, where MAX will select the
maximized value and MIN will select the minimized value.
o The minimax algorithm performs a depth-first search algorithm for the exploration of the
complete game tree.
o The minimax algorithm proceeds all the way down to the terminal node of the tree, then
backtrack the tree as the recursion.
Initial call:
Minimax(node, 3, true)
Working of Min-Max Algorithm:
o The working of the minimax algorithm can be easily described using an example. Below
we have taken an example of game-tree which is representing the two-player game.
o In this example, there are two players one is called Maximizer and other is called
Minimizer.
o Maximizer will try to get the Maximum possible score, and Minimizer will try to get the
minimum possible score.
o This algorithm applies DFS, so in this game-tree, we have to go all the way through the
leaves to reach the terminal nodes.
o At the terminal node, the terminal values are given so we will compare those value and
backtrack the tree until the initial state occurs. Following are the main steps involved in
solving the two-player game tree:
Step-1: In the first step, the algorithm generates the entire game-tree and apply the utility
function to get the utility values for the terminal states. In the below tree diagram, let's take A is
the initial state of the tree. Suppose maximizer takes first turn which has worst-case initial value
=- infinity, and minimizer will take next turn which has worst-case initial value = +infinity.
Step 2: Now, first we find the utilities value for the Maximizer, its initial value is -∞, so we will
compare each value in terminal state with initial value of Maximizer and determines the higher
nodes values. It will find the maximum among the all.
o For node D max(-1,- -∞) => max(-1,4)= 4
o For Node E max(2, -∞) => max(2, 6)= 6
o For Node F max(-3, -∞) => max(-3,-5) = -3
o For node G max(0, -∞) = max(0, 7) = 7
Step 3: In the next step, it's a turn for minimizer, so it will compare all nodes value with +∞, and
will find the 3rd layer node values.
o For node B= min(4,6) = 4
o For node C= min (-3, 7) = -3
Step 4: Now it's a turn for Maximizer, and it will again choose the maximum of all nodes value
and find the maximum value for the root node. In this game tree, there are only 4 layers, hence
we reach immediately to the root node, but in real games, there will be more than 4 layers.
o For node A max(4, -3)= 4
That was the complete workflow of the minimax two player game.
Properties of Mini-Max algorithm:
o Complete- Min-Max algorithm is Complete. It will definitely find a solution (if exist), in
the finite search tree.
o Optimal- Min-Max algorithm is optimal if both opponents are playing optimally.
o Time complexity- As it performs DFS for the game-tree, so the time complexity of Min-
Max algorithm is O(bm), where b is branching factor of the game-tree, and m is the
maximum depth of the tree.
o Space Complexity- Space complexity of Mini-max algorithm is also similar to DFS
which is O(bm).
From the current state, the minimax method in the Figure above computes the minimax
choice. It implements the defining equations directly using a simple recursive computation of
the minimax values of each successor state. As the recursion unwinds, it progresses all the way
down to the tree’s leaves, where the minimax values are then backed up through the tree. In the
figure below, for example, the algorithm recurses down to the three bottom-left nodes and uses
the UTILITY function to determine that their values are 3, 12, and 8, respectively. Then it
takes the smallest of these values, 3 in this case, and returns it as node B’s backed-up value.
The backed-up values of 2 for C and 2 for D are obtained using a similar approach. Finally, we
add the maximum of 3, 2, and 2 to get the root node’s backed-up value of 3.
The minimax algorithm explores the game tree from top to bottom in depth-first. The temporal
complexity of the minimax method is O if the maximum depth of the tree is m and there are b
legal moves at each point (bm). For an algorithm that creates all actions at once, the space
complexity is O(bm), while for an algorithm that generates actions one at a time, the space
complexity is O(m) The time cost is obviously impractical for real games, but this technique
serves as a foundation for game mathematics analysis and more practical algorithms.
Step 2: At Node D, the value of α will be calculated as its turn for Max. The value of α is
compared with firstly 2 and then 3, and the max (2, 3) = 3 will be the value of α at node
D and node value will also 3.
Step 3: Now algorithm backtrack to node B, where the value of β will change as this is a
turn of Min, Now β= +∞, will compare with the available subsequent nodes value, i.e.
min (∞, 3) = 3, hence at node B now α= -∞, and β= 3.
In the next step, algorithm traverse the next successor of Node B which is node E, and the
values of α= -∞, and β= 3 will also be passed.
Step 4: At node E, Max will take its turn, and the value of alpha will change. The current value
of alpha will be compared with 5, so max (-∞, 5) = 5, hence at node E α= 5 and β= 3, where
α>=β, so the right successor of E will be pruned, and algorithm will not traverse it, and the value
at node E will be 5.
Step 5: At next step, algorithm again backtrack the tree, from node B to node A. At node A, the
value of alpha will be changed the maximum available value is 3 as max (-∞, 3)= 3, and β= +∞,
these two values now passes to right successor of A which is Node C.
At node C, α=3 and β= +∞, and the same values will be passed on to node F.
Step 6: At node F, again the value of α will be compared with left child which is 0, and
max(3,0)= 3, and then compared with right child which is 1, and max(3,1)= 3 still α remains 3,
but the node value of F will become 1.
Step 7: Node F
returns the node value 1 to node C, at C α= 3 and β= +∞, here the value of beta will be changed,
it will compare with 1 so min (∞, 1) = 1. Now at C, α=3 and β= 1, and again it satisfies the
condition α>=β, so the next child of C which is G will be pruned, and the algorithm will not
compute the entire sub-tree G.
Step 8: C now returns the value of 1 to A here the best value for A is max (3, 1) = 3. Following
is the final game tree which is the showing the nodes which are computed and nodes which has
never computed. Hence the optimal value for the maximizer is 3 for this example.
Evaluation functions.
Each leaf node had a value associated with it. We had stored this value in an array. But in the
real world when we are creating a program to play Tic-Tac-Toe, Chess, Backgammon, etc. we
need to implement a function that calculates the value of the board depending on the placement
of pieces on the board. This function is often known as Evaluation Function. It is sometimes
also called a Heuristic Function.
The evaluation function is unique for every type of game. In this post, the evaluation function
for the game Tic-Tac-Toe is discussed. The basic idea behind the evaluation function is to give
a high value for a board if the maximizer turn or a low value for the board if
the minimizer turn.
For this scenario let us consider X as the maximizer and O as the minimizer.
Let us build our evaluation function :
If X wins on the board we give it a positive value of +10.
If no one has won or the game results in a draw then we give a value of +0.
We could have chosen any positive/negative. For the sake of simplicity, we chose 10 and shall
use lowercase ‘x’ and lowercase ‘o’ to represent the players and an underscore ‘_’ to represent
a blank space on the board.
If we represent our board as a 3×3 2D character matrix, like char board[3][3]; then we have to
check each row, each column, and the diagonals to check if either of the players has gotten 3 in
a row.
# Python3 program to compute evaluation
# function for Tic Tac Toe Game.
if b[row][0] == 'x':
return 10
else if b[row][0] == 'o':
return -10
if b[0][col]=='x':
return 10
else if b[0][col] == 'o':
return -10
if b[0][0] == 'x':
return 10
else if b[0][0] == 'o':
return -10
if b[0][2] == 'x':
return 10
else if b[0][2] == 'o':
return -10
# Else if none of them have won then return 0
return 0
# Driver code
if __name__ == "__main__":
value = evaluate(board)
print("The value of this board is", value)
Output
The value of this board is 10