Classical Search¶
Agent: goal-based agent called problem solving agent.
Representation: atomic.
Environment: observable, discrete, known, deterministic.
Process:
- Goal formulation -> set of states to consider a goal. Goal helps organize the behavior by limiting the objectives of the agent.
- Problem formulation -> level of detail of actions and states. Avoid too much detail that brings uncertainty.
- Search algorithm -> take problem and output a sequence of actions as solution
- Execution while ignoring percepts
goal <- FORMULATE_GOAL(current_state)
problem <- FORMULATE_PROBLEM(current_state, goal)
solution <- SEARCH(problem)
Problem¶
Definition of state space (a directed graph):
- Initial state
- Actions applicable in s for any state s
- Transition model or successor function
problem.initial_state -> State
problem.actions(state: State) -> list(Action)
# Transition model
problem.result(state: State, action: Action) -> State
# Successor function (no actions() needed, because we can directly get the successors)
problem.successors(state: State) -> list(State)
Defines goal and performance measures:
- Goal test
- Path cost (sum of step costs)
problem.goal_test(state: State) -> bool # or check full environment
problem.step_cost(currstate: State, action: Action, nextstate: State) -> int
An optimal solution has the lowest path cost amongst all solutions.
In problem formulation, abstraction involves removing as much details as possible while retaining validity and ensuring that the abstract actions are easy to carry out.
Examples of problems¶
- Vacuum world
- 8-puzzle -> a sliding-block puzzle (NP complete)
It has 9!/2 reachable states.
- 8-queens incremental formulation: from an empty state, incrementally add queens
States: any arrangement of 0..8 queens
Initial state: empty board
Actions: add a queen to current state
Transition model: state + action => state with added queen
Goal test: 8 queens and none attacking
It has possible sequences to search.
An improvement is to prune the illegal states:
States: any valid arrangement 0..8 queens
Actions: add a queen to any leftmost empty column such that it is not attacked
-
8-queens complete-state formulation: start with all the queens in the board. See Chapter 6 for an efficient algorithm.
-
Route finding problems: commercial travel advice systems
- Touring problems:
States: current position and the set of visited positions
An example of touring problem is TSP. - VLSI layout problems: place cells (cell layout) and wire them (channel routing)
- Robot navigation
- Automatic assembly sequencing: eg. protein design
Search algorithms¶
Frontier/Open list: set of all leaf nodes available for expansion at any given point.
Redundant paths can cause a tractable problem to become intractable. Some problem formulations can eliminate redundant paths (see 8-queens). But in some problems (eg. whose actions are reversible) can't.
Explored set/Closed list: set of all expanded nodes to avoid redundant paths.
By adding a closed list to the infrastructure, the TREE-SEARCH
becomes a GRAPH-SEARCH
.
Infrastructure of search: - Node: a node is not a state, but a bookkeeping of the search. See Node class. - State: the current state - Parent: the previous node - Action: the previous action - Path cost - Frontier data structure: queue (LIFO, FIFO and priority queue) - Closed list data structure: hash table with a right notion of equality between states
Performance measure: - Completeness: if there is solution, it will find one - Optimality: it will find an optimal solution - Time complexity: number of nodes evaluated - Space complexity: number of nodes stored in memory
Time and space complexities are expressed in terms of: 1. Branching factor b
max num of successors 2. Depth d
of the shallowest goal node 3. Max length of any path in the state space m
Effectiveness: - Search cost: time or space used to find the goal - Total cost: search cost + path cost
Uninformed strategies (blind)¶
- Breadth first search
- Frontier: FIFO queue
- Goal test before adding to the frontier
- Completeness: yes, as long as
b
is finite - Optimality: shallowest goal node is the optimal for unit-cost steps
- Time complexity:
O(b^d)
- Space complexity:
O(b^{d-1}
for closed list,O(b^d)
for open list
- Uniform cost search
- Frontier: priority queue with priority lowest
g(n)=path cost
- Goal test when selected for expansion to avoid suboptimality
- Better node replaces the same node in the frontier
- Comleteness: yes, provided every step cost > epsilon
- Optimality: yes
- Time and space complexity:
O(b^{1 + floor(C* / e)})
, whereC*
is optimal cost,e
is minimum action cost. - This is different from breadth first search in that it is optimal for any step cost, but if all step costs are the same, breadth first search is faster.
- Frontier: priority queue with priority lowest
-
Depth first search (tree search)
- Frontier: LIFO queue
- Completeness: no, may loop forever
- Optimality: no
- Time complexity:
O(b^m)
, wherem
is the maximum depth of any node, which may be INF - Space complexity:
O(bm)
-
Depth first search (graph search)
- Frontier: LIFO queue
- Completeness: yes, given state space is finite
- Optimality: no
- Time complexity:
O(b^m)
- Space complexity:
O(b^m)
-
Backtracking search (depth first search):
- Generate only one successor at a time
- Modify the current state rather than copy the state, need to undo modifications
- Space complexity:
O(m)
, one state description andO(m)
actions
-
Depth limited search
- Completeness: yes, given
l >= d
- Optimality: yes, given
l == d
- The diameter of the state space is a good depth limit
- Completeness: yes, given
-
Iterative deepening search (Preferred uninformed when search space is large and the depth d is not known)
- It combines breadth first search and depth first search
- Completeness: yes, given the state space is finite
- Optimality: yes, given the path cost is a nondecreasing function of the depth of the node
- Time complexity:
O(b^d)
as BFS - Space complexity:
O(bm)
A hybrid approach is to run BFS until almost all memory is consumed, then run IDS from all the nodes in the frontier.
- Bidirectional search
- Only when there is an explicit goal state
- Time complexity:
O(b^{d/2})
- Space complexity:
O(b^{d/2})
, one frontier must be in memory, but the other can run IDS
Informed strategies¶
Evaluation function: f(n)
, most include a heuristic function h(n)
, which is the estimated cost of the cheapest path from the state at node n
to a goal state.
- Greedy best first search
f(n) = h(n)
- Completeness: no (tree search, infinite loop), yes (graph search, given finite state space)
- Time complexity:
O(b^m)
- A* search
f(n) = g(n) + h(n)
- Completeness: yes
- Optimality: yes
- Optimally efficient: smallest number of expanded nodes for given heuristic
- Conditions:
- Admissible heuristics:
f(n) < cost of solution path
- Consistent heuristics:
h(n) <= h(n') + c(n, a, n')
, where c is the cost of action - Tree search is optimal if admissible
- Graph search is optimal if consistent, because
f(n)
is nondecreasing
- Admissible heuristics:
- Time complexity:
O(b^{ed})
, only expands nodes withf(n) > C*
, whereC*
is the optimal cost - Space complexity:
O(b^{ed})
, where e is the relative error(h - h*)/h*
, which makes it unfeasible for large state spaces
- Iterative deepening A* search
- DFS
- Increasing limits on
f(n)
f-contour - Completeness: yes, as A*
- Optimality: yes, if heuristics conditions are met
- Time complexity: depends on the number of different heuristic values
- Space complexity:
O(bf*/delta)
, where delta is the smallest step cost and f* is the optimal cost - Excessive node generation if every node has a different
f(n)
- Recursive best first search
- Similar to recursive depth-first search that searches the most optimal successor node but with
f_limit
variable to keep track of the best alternative path available from any ancestor of the current node - Excessive node generation because
h
is usually less optimistic when closer to the goal - Completeness: yes, as A*
- Optimality: yes, if
h
is admissible - Time complexity: depends on how often the best path changes
- Space complexity:
O(bd)
- Similar to recursive depth-first search that searches the most optimal successor node but with
- Simplified memory bounded A*
- A* expanding until the memory = closed list + open list
- Drop the worst leaf node in open list
- For each new successor, the
f(n)
is propagated back up the tree (update occurs after full expansion) - Completeness: yes, if
d < memory size
- Optimality: yes, if reachable in memory size
def smastar(problem, h=None, MAX):
def backup(node):
if completed(node) and node.parent is not None:
oldf = node.f
node.f = least f cost of all successors
if oldf != node.f:
backup(node.parent)
openL = binary tree of binary trees
root = Node(problem.initial)
openL.add(root)
used = 1
# logic
while True:
if len(openL) == 0:
return "failure"
best = openL.best() # deepest least f node
if problem.goal_test(best):
return best
succ = next_successor(best)
succ.f = max(best.f, succ.path_cost + h(succ))
if completed(best): # all successors have been evaluated
backup(best)
if best.expand(problem) all in memory:
openL.remove(best)
used = used + 1
if used > MAX:
deleted = openL.remove_worst()
remove deleted from its parents successors list
openL.add(deleted.parent)
used = used - 1
openL.add(succ)
Heuristics¶
Effective branching factor: N+1 = 1 + b* + (b*)^2 + (b*)^3 + ... + (b*)^d
. The b*
is ideally close to 1. A better heuristics dominates a worse heuristics, hbest(n) > hworse(n)
.
Heuristics can be obtained via relaxation, precomputing patterns, or learning from experience (neural nets, decision trees, reinforcement learning).
To have the best of all heuristics:
h(n) = max {h1(n), h2(n), h3(n), ... }
Disjoint pattern databases: they are additive