(Single-source) shortest-paths problem

Preamble

Given a directed graph, ; :

  • The weight of an edge is
  • The source vertex is

We want to compute the shortest paths, that is, the paths with the smallest total weights, from to all other vertices.

In this graph, we have two shortest-paths from to , . Unreachable nodes have an infinite cost, .

Path

A path is a sequence of vertices where is an edge for each .

Link to original
For example, path .

Weight (path)

The weight of a path is .

Link to original
For example, .

Shortest-path weight

The shortest-path weight (distance) from to is

Link to original

Shortest path

A shortest path from to is any path from to with weight .

Link to original

A subpath of a shortest path, is itself, a shortest path.

Triangle inequality

For each edge :

Holds also if or is not reachable from .

Weights of edges may be negative

Example: negative weights in an application

We use an example from financial analysis, a graph of exchange rates.

Find paths maximising exchange rates:Find shortest paths:
  • For an edge exchange rate from to , e.g. .
  • Set the weight of the edge : (we use natural log, but any fixed base works) e.g.
  • A path from to maximises the combined exchange rate from to , if and only if, this is a shortest path from to according to these edge weights.
  • If , then . We cannot avoid negative weights here, so we solve shortest-paths problem in a graph with (some) edge weights negative.

For a path :

Negative weight cycles

If there is a negative cycle on a path from to , then by going increasingly many times around a cycle, we get paths from to of arbitrarily small (negative) weights.

If there is a negative cycle on a path from to , then by convention, .

In this case, we give up. Computing shortest simple paths in graphs containing negative cycles is NP-hard. (computationally difficult by reduction from Hamiltonian Path problem)

As such we only consider shortest-paths algorithms which:

  • Compute shortest paths for graphs with no negative cycles reachable from source
  • For graphs with negative cycles, detect this and do not compute anything else.

Representing computed shortest paths

If there is no negative cycle reachable from , then shortest paths from to all nodes reachable from are well defined and can be represented by a shortest-paths tree which is a tree rooted at such that for any node reachable from , the tree path from to is a shortest path from to (there may be other shortest paths which are not included in the tree).

A shortest-paths tree can be represented by an array in space (memory), where is the number of nodes in the graph.

is the predecessor of node in tree .

An explicit representation of shortest-paths from with each path represented as a full sequence of all its edges would take space in the worst case.

Output of a shortest-paths algorithm

We compute the shortest-path weights and a shortest-paths tree, or detect a negative cycle reachable from .

Relaxation Technique

For each node , we maintain the shortest-path estimate for (upper bound on weight of shortest path from to ) and the current predecessor of node .

The relaxation technique consists of repeated repeated ‘relaxation’ of edges until we stop making any changes.

Relaxation Algorithm

def relax_init(G, s):
	'''
	Populate table with initial values for parents and distances
	'''
	
	d[s] = 0
	PARENT[s] = None
	
	for node v in V - {s}:
		d[v] = Infty
		PARENT[v] = None
 
def relax_edge(u, v, w):
	'''
	Attempt to relax the edge (u, v) given weights
	'''
	
	if d[v] > d[u] + w(u, v):
		d[v] = d[u] + w(u, v)
		PARENT[v] = u

Properties of Relaxation technique

  1. Non-increasing shortest-path estimates For each node , the shortest-path estimate can only ever decrease.
  2. For each node , the shortest-path estimate is always either equal to (at the beginning) or equal to the weight of some path from to (by induction).
  3. Upper bound property For each node , we always have
  4. No-path property If there is no path from to , then we always have
  5. Convergence property If is a shortest path from to and if at any time prior to relaxing edge , then at all times afterwards.
  6. Path-relaxation property If is a shortest path from to and we relax the edges of in the order , then . This property holds regardless of any other relaxation steps that occur, even if they are intermixed with relaxations of the edges of path .
  7. For each edge in the current parent subgraph (that is ):

    By induction, see LGT.

  8. If the graph contains no negative-weight cycle reachable from , then:
  • the parent subgraph is always a tree rooted at
  • for each node in tree , the weight of the path in from to

  • part of current parent tree (near source vertex ) is already part of computed shortest-paths tree
  • part may change during subsequent relax operations

By induction, see LGT.

  1. When for all then:

    • the parent subgraph is a shortest-paths tree rooted at (by )
    • no further updates possible (by )
  2. The computation can progress, if the shortest-paths weights are not reached yet:

    1. there exists a vertex such that , if and only if,
    2. there exists an edge such that (that is, another effective relax operation is possible)

    : from () and Triangle inequality : assume for some node (so )

    • In the case (no negative cycle on a path from to ) Consider shortest -to- path : Must have an edge on such that but . For such an edge: .
    • In the case for some vertex : (consider a path where is a negative cycle)

Incomplete

The last point in (10) is an “exercise”

Summary for cases with/without negative cycles

If no negative cycle is reachable from :

  • only finite many effective relax operations during computation.
  • PARENT-subgraph is a tree always rooted at (property 8)
  • when eventually no effective relax operation possible, then for each node , (property 10) and PARENT pointers form a shortest-paths tree (property 9)

If a negative cycle is reachable from :

  • there is always an edge such that , that is, effective RELAX operation is not always possible (property 10)
  • PARENT subgraph eventually contains a cycle (not easy to prove; omitted)
  • we can detect the existence of a negative cycle by periodically checking if PARENT pointers form a cycle

Bellman-Ford algorithm

The running time is where is the number of nodes and is number of edges. Worst case running time of any algorithm for the single-source shortest-paths problem with negative weights is .

Bellman-Ford Algorithm

def bellman_ford(G, w, s):
	'''
	Algorithm to solve single-source shortest-paths problem
	Based on the relaxation technique
	'''
	relax_init(G, s) # from relaxation technique
 
	(V, E) = G
	n = |V|
	
	# nodes indexed from 1
	for i = 1 to (n - 1):
		for edge (u, v) in E: # consider in arbitrary order
			relax_edge(u, v, w) # from relaxation technique
	
	for edge (u, v) in E:
		if d[v] > d[u] + w(u, v):
			return False # negative cycle reachable from s
	
	return True # no negative cycles

Correctness of Bellman-Ford algorithm

  • If there is a negative cycle reachable from , then Bellman-Ford algorithm returns false because an effective relax operation will always be possible. In this case, the algorithm is correct.

  • If no negative cycle reachable from , then the following claim is true: At the termination of loop 1, for each vertex .

    Lemma: if the length (no. of edges) of a shortest (simple) path from to a node is , then at the end of iteration (of main loop 1) in the Bellman-Ford algorithm, .

    This lemma follows from the path-relaxation property of the relaxation technique (property 6).

    This lemma implies the claim states above because each simple shortest path has at most edges.

    The claim implies that at the termination of loop 1, no effective relax operation is possible so the algorithm returns true.

    At the end of the computation:

    1. array contains the shortest path distances from to all other nodes;
    2. array contains a shortest-paths tree with node as the source (from above and property 9 of relaxation technique)

    That is, in the case of “no negative cycles”, the algorithm is also correct.

Speeding up Bellman-Ford algorithm

  • Try to decrease number of iterations of loop 1:
    • If no effective relax operations in the current iteration, then terminate (the shortest-path weights are already computed)
    • Periodically check (at end of each iteration of loop 1) if PARENT pointers form a cycle. If they do, terminate and return FALSE: there is a negative cycle reachable from
  • Try to decrease the running time of one iteration of loop 1: consider only edges which may give effective relax operations.
    • Vertex is active if the edges outgoing from have not been relaxed since the last time has been decreased.
    • Perform RELAX on edges outgoing from active vertices.

Bellman-Ford algorithm with FIFO Queue

def bellman_ford_fifo(G, w, s):
	'''
	Algorithm to solve single-source shortest-paths problem
	Builds on Bellman-Ford with some optimisations to cut operations
	'''
	relax_init(G, s) # from relaxation technique
	
	(V, E, Adj) = G
	
	Q = {} # empty queue
	q.enqueue(s)
	
	while Q not empty:
		u = q.dequeue()
		
		for v in Adj[u]:
			if relax_edge(u, v, w):
				# this may be implemented in relax_edge
				# OR relax_edge may return True to trigger
				# this condition:
				if v not in Q:
					Q.enqueue(v)
	
	return True

0 items under this folder.