A* algorithm

written by @marc_lelarge after this thread.

We always assume that the graph we consider is connected (and finite) so that there is always a shortest path between

s and
t
.

Recap: Dijkstra's shortest-path algorithm

See Chapter 4 of Algorithms - Sanjoy Dasgupta, Christos H. Papadimitriou, and Umesh V. Vazirani

Dijkstra's shortest-path algorithm
Input: Graph

G=(V,E); positive edge lengths
{e,eE}
; vertex
sV

Output: For all vertices
u
reachable from
s
, the distance from
s
to
u
:
dist(u)

for all

uV:
    
dist(u)=

    
prev(u)=nil

dist(s)=0

H=makequeue(V,dist)       (using dist-values as keys)
while
H
is not empty:
    
u=deletemin(H,dist)

     for all edges
(u,v)E
:
         if
dist(v)>dist(u)+(u,v)
:
            
dist(v)=dist(u)+(u,v)

            
prev(v)=u

            
decreasekey(H,v)

At the end of the algorithm,

prev will hold for each node
u
the identity of the node immediately before it on the shortest path from
s
to
u
.
The right data structure for
H
is a priority queue which maintians a set of elements (nodes) with associated numeric key values (
dist
) and supports the following operations:

  • Insert. Add a new alement to the set
  • Decrease-key. Accommodate the decrease in key value of a particular element.
  • Delete-min. Return the element with the smallest key, and remove it from the set.
  • Make-queue. Build a priority queue out of the given elements, with the given key values.

Note that each node is added once in

H before the while loop and removed from
H
during an iteration of the while loop. For each node
u
,
dist(u)
can only decrease in this algorithm and is always an upper bound for the true distance from
s
to
u
.

Property : when

u is removed from
H
, then
dist(u)
is the correct distance from
s
to
u
and
prev(u)
is the correct node before
u
in the shortest path from
s
to
u
.

Proof : This can be proved by induction with the following inductive hypothesis: at the end of each iteration of the while loop, the following conditions hold with

u=deletemin(H,dist),
H=H{u}
and
B=VH
: (1) all nodes in
H
are at distance
dist(u)
from
s
and all nodes in
B
are at distance
dist(u)
from
s
, and (2) for every node
v
, the value
dist(v)
is the length of the shortest path from
s
to
v
whose intermediate nodes are constrained to be in
B
(if no such path exists, the value is
).

The base case is straightforward since

s is the first removed element from
H
so that
B={s}
.
We denote by
δ(v)
the true distance between
s
and
v
.
Points (1) and (2) of the inductive hypothesis imply that all nodes
vB
are at
dist(v)
from
s
:
vB,δ(v)=dist(v)
. If this is not the case, by (2), there exists
wH
on the shortest path from
s
to
v
. Since the edge lenghts are positive, the partial path from
s
to
w
is the shortest path between
s
and
w
and its lenght
δ(w)
is strictly less than the distance
δ(v)
between
s
and
v
but by (1)
δ(v)dist(u)
contradicting the fact that
δ(w)dist(u)
. As a result, nodes
vB
have been removed from the queue in increasing order of
dist(v)=δ(v)
.
Assume now that the inductive hypothesis is correct and let
u=deletemin(H)
,
H=H{u}
and
B=VH
. Let
v
be the last node in
B
on the shortest path from
s
to
u
and
w
the node on this path neighbor of
v
and closer to
u
:
svwu
. We have
δ(w)=δ(v)+(v,w)
. By the inductive hypothesis:
δ(v)=dist(v)
and
dist(w)dist(v)+(v,w)=δ(v)+(v,w)
hence
dist(w)=δ(w)
. But since
u=deletemin(H)
, we have
δ(u)dist(u)dist(w)=δ(w)
, so that
u=w
and we proved
dist(u)=δ(u).
Clearly all nodes in
B
are at distance
dist(u)
and (2) is correct. Suppose there exists
xH
with
δ(x)<dist(u)=δ(u)
. We can apply the same argument as above by considering the shortest pasth form
s
to
x
and the last node
v
in
B
:
svwx
so that
dist(v)=δ(w)
and since
wH
:
dist(u)=δ(u)dist(w)=δ(w)δ(x)
, a contradiction. Hence we proved (1).

Modifying Dijkstra's shortest-path algorithm to get A* algorithm

Instead of computing all the shortest paths from

s, we now have a target
t
and want to compute efficiently the shortest path from
s
to
t
.

We have access to a heuristic fucntion

h(u) that estimates the length of the path from any node
u
to the target
t
.

The A* algorithm is a simple variation of the Dijkstra's algorithm with a single modification: the priority in the queue is now the function:

dist(u)+h(u)

A* algorithm
Input: Graph

G=(V,E); positive edge lengths
{e,eE}
; vertex
sV
; a vertex
tV
and an associated heuristic function
h(u)
estimating the distance from
u
to
t
.
Output: under some conditions on the heuristic
h
, a shortest path from
s
to
t
.

for all

uV:
    
dist(u)=

    
prev(u)=nil

dist(s)=0

H=makequeue(V,dist+h)       (using keys:
dist(u)+h(u)
)
while
H
is not empty:
    
u=deletemin(H,dist+h)

     if
u=t
:
         break
     for all edges
(u,v)E
:
         if
dist(v)>dist(u)+(u,v)
:
            
dist(v)=dist(u)+(u,v)

            
prev(v)=u

            if
vH
:
                
insert(H,v)

            
decreasekey(H,v)

We still have that for each node

u,
dist(u)
can only decrease and is always an upper bound for the true distance from
s
to
u
. Note that
s
is the first node removed from
H
(and nerver added back to
H
).

If the heuristic function is zero:

h(u)=0, A* reduces to Dijkstra's algorithm.
In this case, it follows from previous proof that when
dist(v)
is decreased,
v
is always in
H
, hence there is no insertion in
H
and all steps are the same in both algorithms.

A comprehensive path-finding library in javascript.

Accessible here: Demo and GitHub code

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Properties of A* algorithm

Lemma : For an optimal path

s=v0,v1,,vk=t, if
vi
is removed from
H
and all the
vj
's for
j<i
have been removed from
H
then
dist(vi)
is the true distance between
s
and
vi
and
v0,,vi
will never be inserted back into
H
.

Proof : the claim is clearly true for

v0=s. Assume it is true for all
v0,v1,,vi1
and
vi
is removed from
H
. Between the removal of
vi1
and
vi
some other nodes might have been removed from
H
but since
dist(vj)=δ(s,vj)
for all
ji1
, these removals will not modify any of the
dist(vj)
(and not add them back to
H
). Now after removal of
vi1
, since
vi
is a neighbor, we have
dist(vi)=dist(vi1)+(vi1,vi)=δ(s,vi)
.

Consider a variant of A*, where we remove the break. This variant of A* terminates, i.e.

H will become empty after a finite number of iterations since the number of possible values for all the
dist(u)
is finite. Moreover, thanks to previous Lemma, in this variant of A*, when
vi
is last removed from
H
then
dist(vi)
is the true distance between
s
and
vi
(and all the
vj
for
ji
have been removed from
H
). In particular, the only way for A* to fail to return an optimal path is because it removes the target
t
from
H
too early. Under some conditions on the heuristic, we can guarantee that this will nerver happen.

A heuristic function is admissible if it never overestimates the actual cost to get to the goal:

h(u)δ(u,t), where
δ(u,t)
is the distance between
u
and the goal
t
.

A heuristic is consistent (or monotone) if for each edge

(u,v)E,
h(u)(u,v)+h(v)
.

Property : every consistent heuristic is also admissible.

Proof : By definition, we have

h(u)(u,v)+h(v) and we need to prove that
h(u)δ(u,t)
.
Consider a shortest path from
u
to
t
denoted
(u,v1,,vk,t)
. We have
h(vk)(vk,t)+h(t)=(vk,t)
as
h(t)=0
. Then
h(vk1)(vk1,vk)+h(vk)(vk1,vk)+(vk,t)
and so on so that we get
h(u)(u,v1)++(vk,t)=δ(u,t)
.

Property : A* is equivalent to Dijkstra’s algorithm on a graph with reduced lengths

c(u,v)=(u,v)h(u)+h(v). Note that, since Dijkstra’s algorithm requires arc costs to be nonnegative, the heuristic needs to be consistent.

Running Dijkstra's algorithm with the reduced lengths, if

π is the current path from
s
to
v
, we have:
distDijkstra(v)=(u,w)πc(u,w)=(u,w)π(u,w)+h(v)h(s)=distA(v)+h(v)h(s).

The result follows since
h(s)
is a constant and the fact that if
distDijkstra(v)
is updated then
vH
.

As a consequence A* returns an optimal path with reduced costs but since

h(t)=0, this optimal path is also optimal for the original cost.

It turns out, we only need to have an admissible heuristic for A* to find shortest paths:

Property : if the heuristic is admissible, then A* always finds a shortest path.

This can be proved by contradiction. Assume that the path retruned by A* between

s and
t
is not optimal, i.e.
dist(t)>δ(s,t)
when
t
is removed from
H
. Consider
H
just before
t
is chosen. Denote by
s=v0,v1,,vk=t
an optimal path from
s
to
t
. Since
sH
,
dist(s)=0
and
tH
, by previous Lemma, there exists a node
vi
such that for all
ji
,
dist(vj)=δ(s,vj)
and
vi+1H
. But since
t
has been chosen and
h(t)=0
, we have
dist(t)dist(vi+1)+h(vi+1)
. But we have
dist(vi+1)=δ(s,vi+1)
(since
vi
has been removed from
H
and
dist(vi)=δ(s,vi)
) and
h(vi+1)δ(vi+1,t)
(by admissibility). Hence, we get
δ(s,t)dist(t)δ(s,vi+1)+δ(vi+1,t)=δ(s,t)
, a contradiction.

tags: public agreginfo