Algorithm Search⌘K

Proofs: Uniform-cost search

These are the human proofs of Uniform-cost search, at full length.

Uniform-cost search returns a cheapest path, and it stops when costs are bounded below full

This proof shows: correctness, termination.

We use the pseudocode of the page. All action costs are non-negative. For a state tt, δ(t)\delta(t) is the least cost of a path from s0s_0 to tt, and δ(t)=∞\delta(t) = \infty when tt cannot be reached. A pop is live if the node passes line L6, and a state is expanded when a live pop of one of its nodes reaches line L8. The cost of the path PATH(n)(n) is n.gn.g, because line L11 sets gg of a child to gg of its parent plus the cost of the action. So n.g≥δ(n.state)n.g \ge \delta(n.state) for each node.

Facts about the table. (R1) For each state ss, the nodes stored as reached[s][s], one after the other, have strictly decreasing values of gg, by the strict test of line L10. Each of them was pushed when it was stored (lines L11 and L12), or it is the root (lines L2 and L3). (R2) A popped node nn is live if and only if it is the node stored in reached[n.state][n.state] at the time of the pop. If it is, then $n.g = $ reached[n.state].g[n.state].g. If it is not, a later node with a smaller gg replaced it, and line L6 skips nn. (R3) Each node is pushed once and popped at most once.

Lemma 1. At each live pop of a node nn, n.g≤δ(t)n.g \le \delta(t) for each state tt with δ(t)<∞\delta(t) < \infty that was not expanded before this pop.

Proof. By induction on the live pops. Fix a live pop of nn and assume the lemma for all earlier live pops. Then each state xx expanded earlier was expanded at a live pop of a node mm with m.g≤δ(x)m.g \le \delta(x), since xx was not expanded before that pop. With m.g≥δ(x)m.g \ge \delta(x) we get m.g=δ(x)m.g = \delta(x).

Let tt be a state with δ(t)<∞\delta(t) < \infty that was not expanded before the pop of nn. Take a path P=(x0=s0,x1,…,xk=t)P = (x_0 = s_0, x_1, \ldots, x_k = t) of cost δ(t)\delta(t). Each prefix of PP is a cheapest path to its end, because a cheaper path to xjx_j followed by the rest of PP would be cheaper than δ(t)\delta(t). So the prefix up to xjx_j costs δ(xj)\delta(x_j).

Case 1: s0s_0 was not expanded before the pop of nn. Then this is the first live pop. Each node pushed so far is the root, because nodes are pushed only during expansions. So nn is the root, n.g=0≤δ(t)n.g = 0 \le \delta(t).

Case 2: s0s_0 was expanded. The state t=xkt = x_k was not. Let jj be the least index such that xjx_j was not expanded before the pop of nn. Then j≥1j \ge 1, and xj−1x_{j-1} was expanded, at a live pop with g=δ(xj−1)g = \delta(x_{j-1}). During that expansion, line L9 computed g′=δ(xj−1)+c(xj−1,xj)=δ(xj)g' = \delta(x_{j-1}) + c(x_{j-1}, x_j) = \delta(x_j) for the child xjx_j. After lines L10 to L12, reached[xj].g≤δ(xj)[x_j].g \le \delta(x_j), and by (R1) it stays so. It cannot be less than δ(xj)\delta(x_j), because it is the cost of a path. So at the pop of nn, the node $r = $ reached[xj][x_j] has r.g=δ(xj)r.g = \delta(x_j).

The node rr is still in the frontier just before the pop of nn, or r=nr = n. It was pushed, by (R1). If it had been popped earlier, it was the stored node at that time too, because a stored node is only replaced, never restored. So that pop was live by (R2), and xjx_j would have been expanded, which is false. The node nn is popped as a minimum, so n.g≤r.g=δ(xj)≤δ(t)n.g \le r.g = \delta(x_j) \le \delta(t), where the last step uses that the costs of PP after xjx_j are non-negative. If r=nr = n itself, the same inequality holds. □\square

Corollary 2. Each state is expanded at most once, and at each live pop, n.g=δ(n.state)n.g = \delta(n.state).

Proof. Let mm be the node of the first live pop for a state ss. If ss was not expanded before, Lemma 1 with t=st = s gives m.g≤δ(s)m.g \le \delta(s), and m.g≥δ(s)m.g \ge \delta(s) holds for each node, so m.g=δ(s)m.g = \delta(s). After this pop, no node can replace mm in reached[s][s], because by (R1) it would need g<δ(s)g < \delta(s), and no path is that cheap. So mm stays the stored node. By (R3) mm is not popped again, and by (R2) a later pop of another node for ss is stale. So ss has exactly one live pop. □\square

Theorem 3 (soundness and optimality). If the search returns PATH(n)(n) and n.gn.g at line L7, then PATH(n)(n) is a path from s0s_0 to a goal with cost n.g=C∗n.g = C^*.

Proof. PATH(n)(n) follows parent pointers from nn, and each parent link is an action of SUCCESSORS, so it is a path from s0s_0 to n.staten.state, which is a goal by line L7, and its cost is n.gn.g. Let tt be any goal with δ(t)<∞\delta(t) < \infty. If tt was expanded before this pop, line L7 would have returned at that earlier live pop, since tt is a goal. So tt was not expanded before, and Lemma 1 gives n.g≤δ(t)n.g \le \delta(t). Hence n.g≤C∗n.g \le C^*. Since n.gn.g is the cost of a path to a goal, n.g≥C∗n.g \ge C^*. □\square

Theorem 4 (failure is correct). If the search returns failure at line L13, no goal can be reached.

Proof. Suppose that a goal tt is reachable, and take a path s0=x0,…,xk=ts_0 = x_0, \ldots, x_k = t. The loop stops only when the frontier is empty. Then each node that was pushed was popped. For each state in reached, the node stored at the end was pushed by (R1) and popped, and at its pop it was the stored node, so the pop was live by (R2) and the state was expanded. The state s0s_0 is in reached. If xjx_j is in reached, it was expanded, so xj+1x_{j+1} was put in reached at that expansion (line L10 adds a state that is not in the table). By induction tt is in reached and was expanded. Line L7 runs before line L8, so the search returned at that live pop instead of failure. □\square

Theorem 5 (termination). (a) If the branching factor is finite, each action cost is at least ϵ>0\epsilon > 0, and a goal is reachable, the search stops after finitely many steps and returns a path of cost C∗C^*. (b) If the space of reachable states is finite, the search stops for all non-negative costs.

Proof. Each node that is pushed is a distinct path from s0s_0: a child is pushed only at the expansion of its parent node, a node is popped once, and so two pushed nodes with the same path would have two pushed parents with the same path, down to the root, which is pushed once.

(a) Let tt be a goal with δ(t)=C∗\delta(t) = C^*; it exists by the fact that a finite branching factor and costs at least ϵ\epsilon make the minimum attained (see completeness and optimality of search, Fact 1). As long as no goal has been expanded, the proof of Lemma 1, case 2, gives a node in the frontier with g≤δ(t)=C∗g \le \delta(t) = C^* (in case 1 the root has g=0g = 0). So each pop, live or stale, before the search returns has g≤C∗g \le C^*. A path with g≤C∗g \le C^* has at most ⌊C∗/ϵ⌋\lfloor C^*/\epsilon \rfloor actions, and with a finite branching factor there are finitely many such paths. So the number of pops before the return is finite, and each pop does finitely many steps. The loop cannot stop with failure, by Theorem 4. So it returns, and by Theorem 3 the cost is C∗C^*.

(b) Suppose a pushed node has a path that visits a state xx twice, at positions i<ji < j. When the prefix up to position ii was pushed or x=s0x = s_0 was stored, reached[x].g[x].g became at most the cost of that prefix, and by (R1) it never increased. The prefix up to jj costs at least as much, because the costs between ii and jj are non-negative. So the strict test of line L10 refused the prefix up to jj, and it was never pushed, a contradiction because each prefix of a pushed node was pushed. Hence each pushed node is a path without a repeated state. A finite space has finitely many such paths, so the loop runs finitely often. ■\blacksquare

Back to Uniform-cost search