def uniform_cost_search(start): cost_to_get_to_node = {} frontier = PriorityQueue() // Higher Priority equals Lower Cost expanded_nodes = Set() cost_to_get_to_node[start] = 0 frontier.push((start, 0)) expanded_nodes.add(start) while front.has_elements(): u = frontier.pop() if is_goal(u): return path(u) for v in u.successors: if v not in expanded_nodes: if v in frontier: # if we already have it in the frontier, but we found a cheaper way to get there, update the cost to get here. cost_to_get_to_node[v] = min(cost_to_get_to_node[v], cost_to_get_to_node[u] + u.action_cost(v)) else: frontier.push(v) cost_to_get_to_node[v] = cost_to_get_to_node[u] + u.action_cost(v)) return Failure
In general UCS is not complete, because given an infinite number of zero-weight edges deviating away from the goal state, then UCS will follow this path forever and never find the goal. On the other hand, if there exists some such that every edge has at least this weight, then UCS will find the minimum cost solution, this is because it explores nodes in the search space in non-decreasing order of cost so it must find a minimum cost path to a goal before finding any higher cost paths leading to a goal.
path | frontier | about to expand |
(S, 0) | S | |
S | (SP, 1), (SD, 3), (SE, 9) | (SP, 1) |
(SP, 1) | (SD, 3), (SE, 9), (SPQ, 16) | (SD, 3) |
(SD, 3) | (SE, 9), (SPQ, 16), (SDE, 5) | (SDE, 5) |
(SDE, 5) | (SE, 9), (SPQ, 16), (SDEH, 6) | (SDEH, 6) |
(SDEH, 6) | (SE, 9), (SPQ, 16), (SDEHQ, 10) | (SE, 6) |
(SE, 9) | (SPQ, 16), (SDEHQ, 10), (SEH, 10) | (SEH, 10) |
(SEH, 10) | (SPQ, 16), (SDEHQ, 10), (SEHQ, 14) | (SDEHQ, 10) |
(SDEHQ, 10) | (SPQ, 16), (SEHQ, 14), (SDEHQG, 11) | (SDEHQG, 11) |
(SDEHQG, 11) | (SPQ, 16), (SEHQ, 14) |
Note that if we don't have the lower bound assumption, then there could exist some negative edge weights meaning that there is potential for a high cost path, to then eventually become a very low cost before getting to
Suppose that
By the above lemmas we know that UCS will expand all nodes with a cost less than
If we isolate our attention to the subtree with depth
Everything at layer
Let's now calculate how many nodes UCS actually has to expand Since UCS explores nodes with a lower path cost first, then the entire subtree of depth