Lecture 2 - Solving Problems by Searching
Lecture 2 - Solving Problems by Searching
Lecture 2:
Solving Problems by Searching
23 January 2023
1
Admin
2
Teaching Assistants
Gan Pang Yen Guo Mengqi Ivan Lee James Shen Jason
Tan Chee Xiang Tan Ping Zhi Tanveer Singh Udit Singh Wang Cheng 5
Teaching Assistants
7
Plagiarism Policy
Dos
• Discussions without sharing/consulting/taking away any code
• Use ChatGPT with proof (e.g., share links)
Don’ts
• Use codes from those who has done or currently doing the course
• Use codes from the internet without proper citations
• Publish codes to any publicly accessible sites (e.g., GitHub, Google
Drive) or send your codes to anyone
• Minor offense (<10%): final grade lowered by one full letter grade
• Moderate offense (≥10%): failing grade “F”
• Very hard to return to good standing
• Say goodbye to exchange!
9
Materials
10
Credit: Cooking with AMC
Recap
• What is AI?
• History lesson
• PEAS: Performance Measure, Environment, Actuators, Sensors
• Properties of the task environment
• Fully observable, deterministic, episodic, static, discrete, single-agent
• Agents
• Common: reflex, model-based, goal-based, utility-based, learning
11
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
12
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
13
Problem-Solving Agents
When the correct action to take is not immediately obvious, an agent
may need to plan-ahead: to consider a sequence of actions that form a
path to a goal state. Such an agent is called a problem-solving agent,
and the computational process it undertakes is called search.
15
Problem Formulation
Formally, a search problem can be formulated as follows.
• States (state space).
• Initial state: the initial state of the agent
• Goal state(s)/test
• Actions: things that the agent can do
• Transition model: what each action does
• Action cost function: the cost of performing an action
17
Problem Formulation: Vacuum World
18
Problem Formulation: Grid World
19
Problem Formulation: 8-Puzzle
20
Problem Formulation: Robot Assembly
21
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
22
Search Algorithms
A search algorithm takes in a search problem as input and returns a solution
/ failure. It is defined by the order of node expansion.
Evaluation criteria:
• Time complexity: number of nodes generated or expanded
• Space complexity: maximum number of nodes in memory
• Completeness: does it return a solution if it exists?
• Optimality: does it always find the least-cost solution?
24
Representation Invariant
(x,y)=(0,0)
Invalid state
25
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
26
Uninformed Search Algorithms
An uninformed search algorithm is given no clue about how close a
state is to the goal(s).
Condition Algorithm Time Complexity
28
Breadth-first Search
create frontier : queue Sib
Queue:
Sib
29
Breadth-first Search
create frontier : queue Sib
Queue:
30
Breadth-first Search
create frontier : queue Sib
Queue:
31
Breadth-first Search
create frontier : queue Sib
Queue:
32
Breadth-first Search
create frontier : queue Sib
Queue:
33
Breadth-first Search
create frontier : queue Sib
Branching factor b
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action) Pit Sib Sib Buc
1
insert initial state
while frontier is not empty:
state = frontier.pop()
if state is goal: return solution
for action in actions(state):
35
2
1
Priority Queue:
Sib
36
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
if state is goal: return solution
for action in actions(state):
Priority Queue:
1 2 37
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2.
if state is goal: return solution
for action in actions(state): Pit Sib.
Priority Queue:
2 2 3 38
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2. 4 5
if state is goal: return solution
for action in actions(state): Pit Sib . Sib Buc
Priority Queue:
2 3 4 5 39
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 . 4 5
if state is goal: return solution
for action in actions(state): Pit Sib . Sib Buc
3
, 4 ,
return failure
Priority Queue:
3 3 4 4 5 40
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 . 4 5
if state is goal: return solution
for action in actions(state): Pit Sib . Sib Buc
5 4 3
, 4 ,
return failure
Priority Queue:
3 4 4 4 5 5 41
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 . 4 5
if state is goal: return solution
for action in actions(state): Pit Sib . Sib Buc
5 4 3
, 4
,
return failure 5
4 ,
Sib Pit
Priority Queue: ,
,
4 4 4 4 5 5 5 42
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 . 4 5
if state is goal: return solution
for action in actions(state): Pit Sib . Sib Buc
5 4 3
, 4
,
return failure 5
4 ,
,
Sib Pit
Priority Queue: ,
,
4 4 4 5 5 5 43
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 4 5
if state is goal: return solution
for action in actions(state): Pit Sib Sib Buc
5 4 3 4
next state = transition(state, action)
Rim Buc Rim Fag
frontier.add(next state)
return failure 5
4
Sib Pit
Priority Queue:
4 4 4 5 5 5 44
2
1
1 2 1
insert initial state
while frontier is not empty: Rim Fag
state = frontier.pop()
3 2 4 5
if state is goal: return solution
for action in actions(state): Pit Sib Sib Buc
𝐶 ∗ /𝜖 “Tiers”
= 4/1 “Tiers”
5 4 3 4
next state = transition(state, action) 𝐶 ∗ cost of optimal solution
Rim Buc Rim Fag
frontier.add(next state) 𝜖 minimum edge cost
return failure
4 5 • Time complexity (# nodes expanded)?
∗
• 𝑂 𝑏 𝐶 /𝜖
Sib Pit
Priority Queue: • Space complexity?
∗
• 𝑂 𝑏 𝐶 /𝜖
Buc Fag Sib Sib Buc Rim Pit
• Complete? Yes, if 𝜖 > 0 and 𝐶 ∗ finite
• Optimal? Yes, if 𝜖 > 0 45
4 4 4 5 5 5 𝜖 = 0 may cause zero cost cycle
National
Depth-first Search Day
46
National
Depth-first Search Day
Stack:
Sib
47
National
Depth-first Search Day
Stack:
48
National
Depth-first Search Day
Stack:
49
National
Depth-first Search Day
Stack:
Fag Pit
50
National
Depth-first Search Day
Stack:
Fag Pit
51
National
Depth-first Search Day
52
Depth-first Search
create frontier : stack
Sib
Buc
if next state is goal: return solution
frontier.add(next state)
• Time complexity (# nodes generated)?
return failure
• 𝑂 𝑏𝑚
• Space complexity?
• 𝑂 𝑏𝑚
• Complete? No, when depth is infinite or can go back and forth (loops)
• Optimal? No
How do we handle infinite depth? 54
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
55
Depth-limited Search (DLS)
Depth limit l = 2
57
Iterative Deepening Search (IDS)
Depth limit l = 1
58
Iterative Deepening Search (IDS)
Depth limit l = 2
59
Iterative Deepening Search (IDS)
Depth limit l = 2
61
Backward Search
Buc
Search from the goal
Pit Fag
Rim Buc
Sib Sib Buc
62
Bidirectional Search Forward:
Sib
Combine search:
• Forward (from the start)
Rim Fag
• Backward (from the goal)
Backward:
Buc
Stop when two searches meet
Pit Fag
Intuition:
2 × 𝑂 𝑏 𝑑/2 < 𝑂(𝑏 𝑑 ) Issues?
• Operators need to be reversible • How to efficiently check
• Many goal states if a node appears in the
other search tree?63
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
64
Dealing with Repeated States
• Remember states that Sib
65
Tree Search Keep track of visited states Graph Search
(use hashtable/dictionary!)
create frontier create frontier
create visited
insert initial state insert initial state to frontier and visited
while frontier is not empty: while frontier is not empty:
state = frontier.pop() state = frontier.pop()
for action in actions(state): for action in actions(state):
next state = transition(state, action) next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution if next state is goal: return solution
frontier.add(next state) frontier.add(next state)
visited.add(next state)
return failure return failure
66
Graph Search #1 Graph Search #2
create frontier • Expand less states create frontier • Expand more states
• May skip states with less cost • Will not skip states with less cost
create visited create visited
insert initial state to frontier and visited insert initial state to frontier
while frontier is not empty: while frontier is not empty:
state = frontier.pop() state = frontier.pop()
for action in actions(state): if state is goal: return solution
next state = transition(state, action) if state in visited: continue
if next state in visited: continue visited.add(state)
if next state is goal: return solution for action in actions(state):
frontier.add(next state) next state = transition(state, action)
visited.add(next state) frontier.add(next state)
return failure return failure
What’s the difference? There are other variations as well…
67
BFS with Graph Search
create frontier : queue
create visited
insert initial state to queue and visited
while frontier is not empty:
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
68
BFS with Graph Search
create frontier : queue
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
Queue: Visited:
Sib Sib
69
BFS with Graph Search
create frontier : queue
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
Queue: Visited:
70
BFS with Graph Search
create frontier : queue
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib
.
Queue: Visited:
71
BFS with Graph Search
create frontier : queue
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib
. Sib
,
Buc
if next state in visited: continue
if next state is goal: return solution Visited!
frontier.add(next state) (not added to the queue)
visited.add(next state)
return failure
Queue: Visited:
72
BFS with Graph Search
create frontier : queue
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib Sib Buc
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
Queue: Visited:
73
DFS with Graph Search
create frontier : stack
create visited
insert initial state to queue and visited
while frontier is not empty:
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
74
DFS with Graph Search
create frontier : stack
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
Stack: Visited:
Sib Sib
75
DFS with Graph Search
create frontier : stack
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
visited.add(next state)
return failure
Stack: Visited:
76
DFS with Graph Search
create frontier : stack
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib
.
Stack: Visited:
77
DFS with Graph Search
create frontier : stack
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib
.
visited.add(next state)
return failure Visited!
(not added to the stack)
Stack: Visited:
78
DFS with Graph Search
create frontier : stack
Sib
create visited
insert initial state to queue and visited
while frontier is not empty:
Rim Fag
state = frontier.pop()
for action in actions(state):
next state = transition(state, action)
Pit Sib
if next state in visited: continue
if next state is goal: return solution
frontier.add(next state)
Buc Rim
Sib
visited.add(next state)
return failure
Stack: Visited:
79
Choosing a Search Strategy
Depends on the problem:
• Number of goal states
• Distribution of goal states in search tree
• Finite/infinite branching factor/depth
• Repeated states
• Need for optimality?
• Need to know if there is no solution?
80
Summary: Uninformed Search Algorithms
• Search algorithms
• Breadth-first search – queue, explore layer by layer
• Uniform-cost search – priority queue (path cost)
• Depth-first search – stack, go deep first then backtrack
• Variants:
• Depth limited search – limit max depth of the search
• Iterative deepening search – try DLS with depth limit 0, …, N
• Bidirectional search – search from the start and the goal, meet in the middle
• Dealing with repeated states
• Graph search – don’t visit nodes that are already visited
81
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
82
2
3 1 2
Informed Search Algorithms 3
2 2
Uninformed search: 1 1
Sib
Search blindly 1 2
3 0
Rim Fag
Informed search: 2 1 2
2
Use domain information Pit Sib
2 0
83
2
3 1 2
Best-first Search 3
Evaluation function f(n): 2 2
create frontier : priority queue f(n)
estimate the “goodness” of a state
1 1
insert initial state Sib
while frontier is not empty:
state = frontier.pop() 3 0
if state is goal: return solution Rim Fag
Special cases: 2 0
• Greedy best-first search
• A* search
84
2
3 1 2
Greedy Best-first Search 3
Evaluation function f(n): 2 2
create frontier : priority queue f(n)
estimate the “goodness” of a state
1 1
insert initial state Sib
while frontier is not empty:
state = frontier.pop() 3 0
if state is goal: return solution Rim Fag
1 1
insert initial state Sib
while frontier is not empty:
state = frontier.pop() 0 0
if state is goal: return solution Rim Fag
1 1
insert initial state Sib
while frontier is not empty: 1 2
state = frontier.pop() 3 0
if state is goal: return solution Rim Fag
88
Admissible Heuristics: Optimality
Suppose some suboptimal goal 𝐺2 has been generated and is in the fringe. Let n be an
unexpanded node in the fringe such that n is on a shortest path to an optimal goal 𝐺.
𝑓 𝐺 =𝑔 𝐺 +ℎ 𝐺 =𝑔 𝐺 +0
𝑓 𝐺2 = 𝑔 𝐺2 + ℎ 𝐺2 = 𝑔 𝐺2 + 0
𝑔 𝐺2 > 𝑔(𝐺) since 𝐺2 is suboptimal
𝑓 𝐺2 > 𝑓(𝐺)
89
Consistent Heuristics
A heuristic h(n) is consistent if for every node n, every successor n' of n
generated by any action a, h(n) ≤ c(n,a,n') + h(n’), and h(G) = 0.
If h is consistent, we have
f(n’) = g(n') + h(n’)
= g(n) + c(n,a,n') + h(n’)
≥ g(n) + h(n) = f(n)
i.e., f(n) is non-decreasing along any path
Heuristics
• ℎ1 number of misplaces tiles
• ℎ2 total Manhattan distance
ℎ2 dominates ℎ1
If each tile is at most one distance away from
the goal, then ℎ2 = ℎ1 , otherwise ℎ2 > ℎ1
92
“Inventing” Admissible Heuristics
A problem with fewer restrictions on the actions is called a relaxed
problem. The cost of an optimal solution to a relaxed problem is an
admissible heuristic for the original problem.
Original:
A tile can only move to adjacent blank
Relaxations:
• Each tile can move anywhere
• ℎ1 number of misplaces tiles
• Each tile can move to any adjacent square
• ℎ2 total Manhattan distance
93
Outline
• Problem-solving agents
• Search algorithms
• Uninformed search algorithms
• Breadth-first Search (BFS)
• Uniform-cost search
• Depth-first Search (DFS)
• Variants of uninformed search algorithms
• Depth-limited search
• Iterative deepening search
• Bidirectional search
• Dealing with repeated states
• Informed search algorithms
• Greedy best-first search
• A* search
• Heuristics
• Variants of A*
94
Variants of A*
• Iterative Deepening A* (IDA*)
• Use iterative deepening search
• Cutoff using f-cost [ f(n) = g(n) + h(n) ] instead of depth
• Simplified Memory-bounded A* (SMA*)
• Drop the nodes with worst f-cost if memory is full
95
Summary: Informed Search Algorithms
• Informed search: guide search with domain information
• Best-first search
• Greedy best-first search
• f(n) = h(n), heuristic estimate of cost from n to goal
• A* search
• f(n) = g(n) + h(n), cost so far + heuristic
• Heuristics
• Admissible: h(n) ≤ h*(n)
• Consistent: h(n) ≤ c(n,a,n') + h(n’)
• Dominant: if h1(n) ≤ h2(n), h2 dominant
• Creating admissible heuristic: true cost of the relaxed problem
• A* variants: IDA*, SMA*
• Idea: prune to save memory
96
Summary
• Problem-solving agents
• Uninformed search algorithms
• Breadth-first Search (BFS) – layer by layer
• Uniform-cost search – Djikstra
• Depth-first Search (DFS) – go deep first
• Variants of uninformed search algorithms
• Depth-limited search – set max depth
• Iterative deepening search – try DLS with depth limit 0, …, N
• Bidirectional search – combine forward and backward search
• Dealing with repeated states – visit state only once
• Informed search algorithms
• Greedy best-first search – f(n) = h(n)
• A* search – f(n) = g(n) + h(n)
• Heuristics: admissibility, consistency, dominance
• Variants of A*: IDA*, SMA*
97
Coming Up Next Week
• Local search
• Hill climbing
• Simulated annealing
• Beam search
• Genetic algorithms
• Adversarial search
• Games vs search problems
• Minimax
• Alpha-beta pruning
98
To Do
• Lecture Training 2
• +100 Free EXP
• +50 Early bird bonus
• Problem Set 0
• Due Saturday, 27th January
99