Proofs: Bidirectional Dijkstra
These are the human proofs of Bidirectional Dijkstra, at full length.
Bidirectional Dijkstra returns a shortest path full
This proof shows: correctness, termination.
Claim. Let be a directed graph with weights and let be vertices. BIDIRECTIONAL-DIJKSTRA returns . If , the returned vertex sequence is a walk from to of weight , and it is a path when all weights are positive.
Termination. Each side inserts an entry into its queue only when line L9 lowers a label, which happens at most once per scan of an edge, and each vertex is marked done at most once per side. So each queue receives at most entries, each pass of the loop removes one entry, and the loop ends after at most passes, or earlier by line L4. When both queues are empty, line L4 sees and stops.
Notation. The forward search runs on from ; its distances are . The backward search runs on the reversed graph from ; its distances are . Write for the least key in , with .
Step 1: facts about each side. Each side, on its own, is Dijkstra's algorithm with a lazy-deletion heap; the other side only reads its labels in line L10. So the following hold for each side , from the proof of Dijkstra's algorithm:
- (a) always, and if , following from gives a path to the root of side of weight exactly (forward: from to ; backward: from to ).
- (b) When is marked done on side , , and the label never changes after that.
- (c) At any moment, every vertex with is done on side .
For (c): let be a vertex with not done on side , and let be a shortest path to on side . Its first vertex is done or is the root with its entry still in . Let be the first vertex of not done; if is the root, its entry is in the queue; otherwise its predecessor on is done, so by (b) and the relaxation of that edge, and the entry is in . So , since weights are nonnegative. This is the contrapositive of (c).
Step 2: is an upper bound. When line L10 sets from an edge scanned on the forward side, is the weight of a path and is the weight of a path by (a), so is the weight of the walk . The backward case is symmetric, with the edge used in its original direction. So at all times, and if , from line L2.
Step 3: at the stop, . Suppose , the loop stops, and . Then ; let be a shortest path. Let and at the stop, so . For each , , so or .
Call forward if . Since does not decrease along , the forward vertices are for some ( meaning none), and the others satisfy . By (c), forward vertices are done forward and the others are done backward.
- If , the edge joins a vertex done forward to a vertex done backward.
- If , all of is done backward. Take the edge ; its first end is with from line L1 on.
- If , all of is done forward. Take the edge ; its last end is with .
In each case let be that edge. Consider the moment when the later of "x done forward" and "y done backward" happened; in the cases and , consider when was done backward or was done forward, respectively. If that moment was the forward scan of , line L10 examined with and (final by (b), or 0 at ). If it was the backward scan of , line L10 examined the reversed edge with and . Either way, afterwards , since is a shortest path and its sub-paths are shortest. As never increases, this contradicts . Here , since is a path and , so line L10, which skips only self-loops, does examine .
So by Steps 2 and 3. In particular, exactly when is not reachable from .
Step 4: the path. If and , let be the edge remembered when took its final value, scanned on side . At that time . Labels only decrease, so at the end . By (a), gives a path of weight and gives a path of weight . The joined walk has weight at most , hence exactly . Each chain is a path. If the two chains share a vertex , the walk contains the closed walk ; its weight is 0, because cutting it would leave an - walk lighter than otherwise. With all weights positive no closed walk has weight 0, so the chains are disjoint and the sequence is a path.