Download - Lecture 2

Document related concepts
no text concepts found
Transcript
Artificial Intelligence:
Search and Mining
Lecture 2
Masashi Shimbo
2016-04-19
Today’s agenda
▶
▶
Brief review of the last class
More on tree search:
▶
▶
▶
Depth-first search
Iterative deepening depth-first search
Uniform-cost tree search
2 / 76
Review (+ Supplement)
What we learned in the last class (1)
▶
State space = (possibly huge) graph
▶
“Search” is a task of finding a path in state space, from the
initial state to a goal state
— preferably the one with the least cost (shortest path)
4 / 76
State space is a labeled graph (V, A, c)
where
▶
V = set of nodes/vertices (states)
▶
|V| may be huge (even infinite)
▶
A ⊂ V × V = set of edges/arcs (actions)
▶
c : A 7→ R+ = label (cost) function (i.e., label = cost)
with
▶
a specific node s ∈ V called initial state, and
▶
a set G ⊂ V of goal states.
5 / 76
Tree graphs with identical costs
For the ease of discussion, we assumed:
▶
▶
all action costs are identical
the state space is a tree rooted at the initial state
A (rooted) tree is a graph such that:
▶
every node in the graph has exactly one path from
the root (initial) node.
6 / 76
Rooted tree: example
s
root (initial) node
7 / 76
Tree with uniform branching factor b = 2
s
root (initial) node
8 / 76
What we learned in the last class (2)
Difference in many search algorithms can be accounted
for by the order in which nodes are expanded.
In a tree-like state space, each can be regarded as a
variation of the General Tree Search algorithm…
9 / 76
General Tree Search algorithm template
1
2
3
4
5
6
7
8
OPEN ← new List
Insert(OPEN, s)
loop do
if OPEN is empty then return “failure”
v ← RemoveOne(OPEN)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Expand(v) do
Insert(OPEN, u)
Different implementations of data structure List and its associated
functions RemoveOne() and Insert() lead to different search
algorithms
10 / 76
What is the role of the list OPEN?
OPEN maintains the frontier nodes of the explored state space
In the beginning:
▶
OPEN contains s only
In each iteration:
▶
A state is picked up (and removed) from OPEN
(with function RemoveOne)
▶
It is Expanded → all successor states are “generated”
▶
The generated states are added to OPEN
(with function Insert)
11 / 76
OPEN and expanded nodes during search
12 / 76
OPEN and expanded nodes during search
OPEN = nodes at the frontier
13 / 76
OPEN and expanded nodes during search
OPEN = nodes at the frontier
expanded nodes
14 / 76
What we learned in the last class (3)
Using different data structure List, together with
functions RemoveOne() and Insert(), leads to different
search strategies.
Setting
List
= Queue
RemoveOne = Dequeue
Insert
= Enqueue
will make the breadth-first search algorithm.
15 / 76
Breadth-first search
Input : initial state s
Output : a solution path, if found, or “failure”
1
2
3
4
5
6
7
8
OPEN ← new List Queue
Insert Enqueue(OPEN, s)
loop do
if OPEN = ∅ then return “failure”
v ← RemoveOne Dequeue(OPEN)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Expand(v) do
Insert Enqueue(OPEN, u)
16 / 76
Breadth-first search: properties
BFS is complete
BFS never fails to find a goal, even if the state space
is infinite.
BFS is not admissible
BFS returns the first shallowest solution path it
finds. In general, the shallowest solution path
might not be the one with the least cost.
It is, however, admissible if all actions have an
equal cost.
17 / 76
Breadth-first search: worst-case complexity
in a tree with branching factor b and shallowest goal depth d
Time complexity
In the worst case, all nodes up to depth d, and some
nodes at depth (d + 1) are generated.
O(bd+1 )
Space complexity
Same as the time complexity, because BFS maintains
information (Parent[]) of all generated nodes on
memory. Hence
O(bd+1 )
18 / 76
Depth-first search
Problem with breadth-first search
Memory inefficient
Space complexity in a tree with branching factor b:
O(bd+1 )
because BFS maintains all generated nodes on
memory
▶ b: branching factor of the tree
▶ d: depth of the shallowest goal state
20 / 76
Depth-first search
Uses Stack (LIFO list; “last-in first-out” list) to order node
expansion
21 / 76
Stack
LIFO (“Last-in first-out”) buffer
Functions for manipulating stacks:
▶
▶
Push(S , v) — Insert item v at the beginning of list S
Pop(S ) — Remove the first item in the list S and
return it
22 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
23 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
24 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
25 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
26 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
27 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
28 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
29 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
30 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
31 / 76
Stack: examples
S :
S :
Push(S ,
1
2
a
b
1
2
3
c
a
b
1
S : d
c )
S :
Push(S , d )
2
3
4
c
a
b
v ← Pop(S )
1
2
3
c
a
b
1
S : d
2
3
4
c
a
b
v: d
S :
1
2
3
c
a
b
32 / 76
General tree search algorithm
Input : initial state s
Output : a solution path, if found, or “failure”
1
2
3
4
5
6
7
8
OPEN ← new List
Insert(OPEN, s)
loop do
if OPEN is empty then return “failure”
v ← RemoveOne(OPEN)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Expand(v) do
Insert(OPEN, u)
33 / 76
Depth-first search
Input : initial state s
Output : a solution path, if found, or “failure”
1
2
3
4
5
6
7
8
OPEN ← new List Stack
Insert Push(OPEN, s)
loop do
if OPEN is empty then return “failure”
v ← RemoveOne Pop(OPEN)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Expand(v) do
Insert Push(OPEN, u)
34 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: s
b
e
t
d
goal state
f
g
h
i
35 / 76
Depth-first search: a sample run
initial state
s
Expanded state: s
a
c
OPEN:
b
e
t
d
goal state
f
g
h
i
36 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: a b
b
e
t
d
goal state
f
g
h
i
37 / 76
Depth-first search: a sample run
initial state
s
Expanded state: a
a
c
OPEN: b
b
e
t
d
goal state
f
g
h
i
38 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: c d b
b
e
t
d
goal state
f
g
h
i
39 / 76
Depth-first search: a sample run
initial state
s
Expanded state: c
a
c
OPEN: d b
b
e
t
d
goal state
f
g
h
i
40 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: d b
b
e
t
d
goal state
f
g
h
i
41 / 76
Depth-first search: a sample run
initial state
s
Expanded state: d
a
c
OPEN: b
b
e
t
d
goal state
f
g
h
i
42 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: f g b
b
e
t
d
goal state
f
g
h
i
43 / 76
Depth-first search: a sample run
initial state
s
Expanded state: f
a
c
OPEN: g b
b
e
t
d
goal state
f
g
h
i
44 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: g b
b
e
t
d
goal state
f
g
h
i
45 / 76
Depth-first search: a sample run
initial state
s
Expanded state: g
a
c
OPEN: b
b
e
t
d
goal state
f
g
h
i
46 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: b
b
e
t
d
goal state
f
g
h
i
47 / 76
Depth-first search: a sample run
initial state
s
Expanded state: b
a
c
OPEN:
b
e
t
d
goal state
f
g
h
i
48 / 76
Depth-first search: a sample run
initial state
s
Expanded state:
a
c
OPEN: t e
b
e
t
d
goal state
f
g
h
i
49 / 76
Depth-first search: a sample run
initial state
s
Expanded state: t
a
c
OPEN: e
b
e
t
d
goal state
f
g
h
i
50 / 76
Depth-first search is not complete, nor is
admissible
May not terminate if the state space is infinite
It returns the first (leftmost) solution however bad its
quality is.
51 / 76
Depth-first search
Additional improvement
▶
As soon as all descendants of a node have been expanded, the
node can be removed from memory
å required memory is linear in the number of nodes in OPEN
▶
For a uniform tree with branching factor b, when depth-first
search expands a node at depth k, at most O(bk) nodes are
stored in OPEN
å required memory is linear in the depth of the state space
52 / 76
Depth-first search
Memory-efficient, recursive implementation
Main function:
Input : initial state s
1
2
function DFS(s)
return RecursiveDFS(s, s)
Simply call function RecursiveDFS(s, s), which is to be explained in
the next slide…
53 / 76
Depth-first search
Memory-efficient, recursive implementation (continued)
Sub-routine: RecursiveDFS
Input : state v to start depth-first search
Input : initial state s
Output : a solution, if found, or “failure”
1
2
3
4
5
6
7
function RecursiveDFS(v, s)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Succ(v) do
Parent[u] ← v
# memorize parent of u
result ← RecursiveDFS(u, s)
# search below u
if result , “failure” then return result
remove information associated with u from memory # such
as Parent[u], which is no longer needed
8
return “failure”
54 / 76
Worst case complexity
Time complexity
In the worst case all nodes in the state space will be
expanded. Hence, O(bm ) where m is the maximum
depth of any node.
Space complexity
O(bm)
55 / 76
Iterative deepening depth-first search
How to overcome incompleteness of depth-first search?
Iterative deepening depth-first search
Depth-first search is memory efficient but is incomplete
in infinite state space
Iterative deepening is complete and enjoys the linear
memory requirement of depth-first search
57 / 76
Iterative deepening: idea
Introduce a cutoff depth θ to depth-first search
— backtrack immediately if the node depth exceeds θ
Successively run depth-first searches with increasing
cutoff depth θ = 1, 2, . . .
58 / 76
Iterative deepening: a sample run
initial state
goal state
unbounded path
59 / 76
Iterative deepening: a sample run
initial state
Cutoff depth = 1
No goal states with depth less than
or equal to 1
goal state
Ô Depth-first search fails.
unbounded path
60 / 76
Iterative deepening: a sample run
initial state
Cutoff depth = 2
No goal states with depth less than
or equal to 2
goal state
Ô Depth-first search fails.
unbounded path
61 / 76
Iterative deepening: a sample run
initial state
Cutoff depth = 3
A goal state exists at depth 3.
goal state
Ô Depth-first search succeeds.
unbounded path
62 / 76
Space complexity
Since it performs a series of depth-first searches (with
different depth-limits) up to the solution depth d,
O(bd)
63 / 76
Time complexity
▶
▶
▶
Depth 1 nodes are generated d times.
Depth 2 nodes are generated d − 1 times.
..
.
Depth d nodes are generated once.
(# of nodes at depth d) = bd
(b: branching factor)
1bd + 2bd−1 + 3bd−2 + · · · + (d − 1)b2 + db = O(bd )
64 / 76
Summary: Tree search algorithms
Iterative
Search algorithm Breadth-first Depth-first Deepening
Completeness
yes
no
yes
Admissibility
no/yes*
no
no/yes*
d+1
m
Time complexity
O(b )
O(b )
O(bd )
Space complexity
O(bd+1 )
O(bm)
O(bd)
* admissible if action costs are all identical.
b : branching factor
d : depth of the shallowest goal state
m : maximum depth of the state space
Admissibility of breadth-first and iterative deepening searches are shown as “no/yes*,” to make it clear
that in general these algorithms are not admissible (if action costs vary).
65 / 76
Uniform-cost tree search
How do we take edge (action) costs into account?
Uniform-cost tree search
Cost-aware extension of the breadth-first search
67 / 76
Breadth-first search
1
2
3
4
5
6
7
8
OPEN ← new Queue
Enqueue(OPEN, s)
loop do
if OPEN = ∅ then return “failure”
v ← Dequeue(OPEN)
if IsGoal(v) then return Solution(v, s)
foreach u ∈ Expand(v) do
Enqueue(OPEN, u)
68 / 76
Uniform-cost tree search expands nodes with
the cheapest cost first
To make this possible,
▶
For each node n, maintain the path cost from the
initial node.
g[v] = path cost from the initial state to v
▶
Use a priority queue for the OPEN list — to select
the node with the minimum g-value in OPEN.
69 / 76
Function Expand(v)
now maintains the cost g from the initial state
Input : state v to expand
Output : set of successors of n
1
2
3
4
5
6
7
S ← ∅;
foreach node u ∈ Succ(v) do
Reserve memory for node u
Parent[u] ← v
g[u] ← g[v] + c(u, v)
S ← S ∪ {u}
return S
70 / 76
Function Expand(v)
v
c(v, u1 )
u1
c(v, u2 )
u2
c(v, u3 )
u3
71 / 76
Function Expand(v)
v
c(v, u1 )
u1
c(v, u2 )
u2
c(v, u3 )
u3
Succ(v)
72 / 76
Function Expand(v)
v
c(v, u1 )
u1
Parent[u1 ] = v
g[u1 ] ← g[v] + c(v, u1 )
c(v, u2 )
u2
Parent[u2 ] = v
g[u2 ] ← g[v] + c(v, u2 )
c(v, u3 )
u3
Parent[u3 ] = v
g[u3 ] ← g[v] + c(v, u3 )
73 / 76
Priority queue
Two functions for manipulating priority queue Pg :
Insert(Pg , v)
Put item v in Pg .
DeleteMin(Pg )
Remove and return an item with the minimum
g-value from Pg . Thus, the returned item v is the
one with
v = argmin g[u]
u∈Pg
before its removal
74 / 76
Uniform-cost tree search
1
2
3
4
5
6
7
8
OPEN ← new PriorityQueueg
Insert(OPEN, s)
loop do
if OPEN is empty then return failure
n ← DeleteMin(OPEN)
if IsGoal(n) then return Solution(n)
foreach m ∈ Expand(n) do
Insert(OPEN, m)
75 / 76
What about search algorithms for general graphs?
(not just trees?)
We’ll find them out in the next class.
76 / 76
Related documents