Bellman–Ford algorithm

This is an old revision of this page, as edited by 203.200.43.195 (talk) at 17:00, 12 March 2005. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Bellman-Ford algorithm computes single-source shortest paths in a weighted graph (where some of the edge weights may be negative). Dijkstra's algorithm accomplishes the same problem with a lower running time, but requires edges to be non-negative. Thus, Bellman-Ford is usually used only when there are negative edge weights.

Bellman Ford runs in O(VE) time, where V and E are the number of vertices and edges. Hi Mama

Here is a sample algorithm of Bellman-Ford

BF(G,w,s) // G = Graph, w = weight, s=source
Determine Single Source(G,s);
set Distance(s) = 0; Predecessor(s) = nil;
for each vertex v in G other than s, 
   set Distance(v) = infinity, Predecessor(v) = nil;
for i <- 1 to |V(G)| - 1 do   //|V(G)| Number of vertices in the graph
   for each edge (u,v) in G do
      if Distance(v) > Distance(u) + w(u,v) then
         set Distance(v) = Distance(u) + w(u,v), Predecessor(v) = u;  
for each edge (u,r) in G do
   if Distance(r) > Distance(u) + w(u,r);
      return false; //This means that the graph contains a cycle of negative weight 
                    //and the shortest paths are not well defined
return true; //Lengths of shortest paths are in Distance array

Proof of correctness

The correctness of the algorithm can be shown by induction. The precise statement shown by induction is:

Lemma. After i repetitions of for cycle:

  • If Distance(u) is not infinity, it is equal to the length of some path from s to u;
  • If there is a path from s to u with at most i edges, then Distance(u) is at most the length of the shortest path from s to u with at most i edges.

Proof. For the base case of induction, consider i=0 and the moment before for cycle is executed for the first time. Then, for vertex s, Distance(s)=0 which is correct. For other vertices, Distance(u)=infinity which is also correct because there is no path from s to u with 0 edges.

For the inductive case, we first prove the first part. Consider a moment when Distance is updated by Distance(v) = Distance(u) + w(u,v) step. By inductive assumption, Distance(u) is the length of some path from s to u. Then, Distance(u) + w(u,v) is the length of the path from s to v that first goes from s to u and then from u to v.

For the second part, consider the shortest path from s to u with at most i edges. Let v be the last vertex before u on this path. Then, the part of the path from s to v is the shortest path between s to v with i-1 edges. By inductive assumption, Distance(v) after i-1 cycles is at most the length of this path. Therefore, Distance(v)+w(u,v) is at most the length of the path from s to u. In the ith cycle, Distance(u) gets compared with Distance(v)+w(u,v) and set equal to it, if Distance(v)+w(u,v) was smaller. Therefore, after i cycles Distance(u) is at most the length of the path from s to u.

End of proof.

The correctness of the algorithm follows from the lemma together with the observation that shortest path between any two vertices must contain at most V(G)-1 edges. (If a path contained more than V(G)-1 edges, it must contain some vertex v twice. Then, it can be shortened by removing the part between the first occurrence of v and the second occurrence. This means that it was not the shortest path.)

Implementations

/****************************************/
/*Author: Chiam Jia-Han a.k.a JellyWorld*/
/*Copyright: This code is distributed   */
/*unconditionally.  You may use it      */
/*without author acknowledgement.       */
/****************************************/
#define INFINITY ((int) pow(2, sizeof(int)*8-2)-1)

typedef struct
{
	int source;
	int dest;
	int weight;
}Edge;

void BellmanFord(Edge edges[], size_t edgecount, size_t nodecount, size_t source)
{
	int* distance = (int*) malloc(nodecount*sizeof(int));
	for(int i = 0; i < nodecount; i++)
	{
		if(i == source) distance[i] = 0;
		else distance[i] = INFINITY;
	}
	for(int i = 0; i < nodecount; i++)
	{
		for(int j = 0; j < edgecount; j++)
		{
			if(distance[edges[j].dest] > distance[edges[j].source] + edges[j].weight)
			{
				distance[edges[j].dest] = distance[edges[j].source] + edges[j].weight;
			}
		}
	}
	for(int i = 0; i < edgecount; i++)
	{
		if(distance[edges[i].dest] > distance[edges[i].source] + edges[i].weight)
		{
			printf("Error occurred. Negative edge weight cycles detected");
			break;
		}
	}
	for(int i = 0; i < nodecount; i++)
	{
		printf("The shortest distance between nodes %i and %i is %i", source, i, distance[i]);
	}
}
Program written by Chiam Jia-Han a.k.a JellyWorld


segment .model

segment .stack

segment .data

INFINITY dd 1
format_string1 db "Error occurred. Negative edge weight cycles detected", 0
format_string2 db "The shortest distance between nodes %i and %i is %i", 0
extern _printf
extern _malloc
extern _exit

segment .bss

distance resd 1

segment .text
        global  _BellmanFord
_BellmanFord:			    ;Function takes in same parameters as C function above
	mov eax, INFINITY           ;Load Infinity into register eax
	shl eax, 29		    ;Shift register 29 bits left
	mov dword [INFINITY], eax   ;Define INFINITY as 2^29
	push ebp		    ;Store ebp register in stack
	mov ebp, esp		    ;Fix ebp to stack pointer
	mov eax, [ebp+16]	    ;Store third parameter in eax
	shl eax, 2		    ;Bitshift it
	push eax		    ;Push it onto stack as parameter for malloc
	call _malloc		    ;Call malloc
	pop edx			    ;Pop it back off the stack
	shl eax, 2		    ;Multiply return value by 4
	mov dword [distance], eax   ;Store pointer returned in distance
	mov ecx, [ebp+16]	    ;Store nodecount in ecx
	sub ecx, 1		    ;Subtract one
	loopend1:		    ;Start of loop
	shl ecx, 2		    ;Multiply by 4
	lea eax, [distance+ecx]	    ;Store pointer in eax
	shr ecx, 2		    ;Divide by 4
	cmp ecx, [ebp+20]	    ;Check for equality with source node
	jnz dinf		    ;Jump to"else" clause if equality not detected
	mov dword [eax], 0	    ;Change value at pointer to 0
	jmp end1		    ;Go to end of loop
	dinf:			    ;Else Clause
	mov edx, [INFINITY]	    ;Store value in edx
	mov dword [eax], edx        ;Set value to infinity
	end1:			    ;End of loop label
	loop loopend1		    ;Return to front of loop
	mov ecx, [ebp+16]	    ;Reload nodecount into register eax
	dec ecx                     ;Decrement ecx
	loopend2:		    ;Start of loop label
	mov ebx, 0		    ;Set ebx to 0
	innerloop1:		    ;Inner Loop label
	mov edx, [ebp+12]	    ;Store edgecount variable in edx
	cmp edx, ebx		    ;Compare for equality
	jz end2			    ;Skip to loop end if they are equal
	mov eax, ebx		    ;Store ebx in eax
	add eax, edx		    ;Add the registers
	mov edx, [ebp+8]	    ;Load edge array into edx
	push edx		    ;Store edx on the stack temporarily (mul instruction modifies edx)
	push 12 		    ;Push 12 onto the stack
	mul dword [esp]		    ;Multiply 12 with eax
	add esp, 4		    ;Pop 12 off the stack
	pop edx			    ;Push it back off the stack
	mov edx, eax		    ;Set edx to eax
	add edx, 4		    ;Point to dest member
	mov eax, [edx]              ;Load into eax
	shl eax, 2		    ;Multiple by 4
	lea eax, [distance+eax]     ;Access member of distance array
	push dword [eax]	    ;Push eax
	push eax		    ;Push eax pointer
	sub edx, 4		    ;Point edx to source member
	mov eax, [edx]		    ;Store value at edx in eax
	shl eax, 2		    ;Multiply by 4
	lea eax, [distance+eax]	    ;Access member of distance array
	push dword [eax]	    ;Store on stack
	push eax		    ;Push eax onto stack
	add edx, 8		    ;Point to weight member
	push dword [edx]	    ;Push onto stack
	push edx		    ;Push edx onto stack
	mov eax, [esp+4]	    ;Take value off top of stack and store in eax
	add eax, [esp+12]	    ;Add top two dwords on stack
	cmp eax, [esp+20]	    ;Compare with first
	jz after		    ;Jump to label after if eax = [esp+20]
	jns label1		    ;Looks complicated
	jmp label2		    ;but is basically
	label1:			    ;the same as
	jo after		    ;the C/C++ equivalent of
	jmp start2		    ;if(eax < [esp+20])
	label2:			    ;{
	jno after		    ;	//Bla bla bla
	start2:			    ;}   
	mov edx, [esp+16]	    ;Edx = [esp+16]
	mov dword [edx], eax	    ;Set [edx] = eax
	after:			    ;Label after if clause
	add esp, 24		    ;Push EVERYTHING off the stack
	inc ebx			    ;Increment loop counter
	jmp innerloop1	    	    ;Jump to start of inner loop
	end2:			    ;End of loop label
	cmp ecx, 0		    ;Check if 0
	jz outside		    ;Break loop
	dec ecx			    ;Decrement ecx
	jmp  loopend2    	    ;Jump to start of outer loop
	outside:
	mov eax, 0		    ;Reset the registers
	mov ebx, 0		    ;Reset the registers
	mov ecx, 0		    ;Reset the registers
	mov edx, 0		    ;Reset the registers
	mov ecx, [ebp+12]	    ;Load nodecount parameter
	dec ecx			    ;Decrement ecx
	loopstart2:		    ;Start of loop
	mov edx, [ebp+8]	    ;Load into edx
	add edx, ecx		    ;Add edx and ecx
	push edx		    ;Temporarily store edx on stack
	push 12			    ;Store multiplier on stack
	mov eax, edx		    ;Store edx in eax
	mul dword [esp]		    ;Multiply eax (ie. edx) by 12
	add esp, 4		    ;Pop off 12
	pop edx			    ;Pop edx back off
	mov edx, eax		    ;Move the result in eax into edx
	add edx, 4		    ;Add 4 to access dest member
	mov eax, [edx]		    ;Move value of dest member into eax
	shl eax, 2		    ;Multiply by 4
	add eax, distance	    ;Make it point to index in distance array
	push dword [eax]	    ;Store on stack
	sub edx, 4		    ;Access source member
	mov eax, [edx]		    ;Move value of source member into eax
	shl eax, 2		    ;Multiply by 4
	add eax, distance	    ;Make it point to index in distance array
	push dword [eax]	    ;Store value on stack
	add edx, 8		    ;Point to weight member
	push dword [edx]	    ;Push onto stack
	mov eax, [esp]		    ;Store in eax
	add eax, [esp+4]	    ;Add to previous stack value
	cmp eax, [esp+8]	    ;Compare two values
	jz cafter		    ;Jump to label after if eax = [esp+20]
	jns clabel1		    ;Looks complicated
	jmp clabel2		    ;but is basically
	clabel1:		    ;the same as
	jo cafter		    ;the C/C++ equivalent of
	jmp cstart2		    ;if(eax < [esp+8])
	clabel2:		    ;{
	jno cafter		    ;	//Bla bla bla
	cstart2:		    ;}
	add esp, 8		    ;Pop those values off
	push format_string1	    ;Push format string onto the stack
	call _printf		    ;Call printf()
	add esp, 4		    ;Pop format string off
	push 1			    ;Push one onto stack
	call _exit		    ;Quit program
	cafter:			    ;cafter label
	cmp ecx, 0		    ;Check if ecx is 0
	jz exitloop		    ;If it is, break the loop
	dec ecx			    ;Decrement ecx
	jmp loopstart2		    ;Jump to the front
	exitloop:
	mov eax, 0		    ;Reset the registers
	mov ebx, 0		    ;Reset the registers
	mov ecx, 0		    ;Reset the registers
	mov edx, 0		    ;Reset the registers
	loopstart3:		    ;Loop label
	mov ecx, eax		    ;Move ecx into eax
	shl eax, 2		    ;Multiply by 4
	add eax, distance	    ;Add distance to eax
	push dword [eax]	    ;Push onto stack
	push ecx		    ;Push onto stack
	push dword [ebp+20]	    ;Push source onto stack
	push format_string2	    ;Push format string onto stack
	call _printf		    ;Call printf
	add esp, 12		    ;Pop parameters off the stack
	inc ecx			    ;Increment ecx
	cmp ecx, [ebp+16]	    ;Compare with nodecount
	jz outside3		    ;Quit if equal
	jnz loopstart3		    ;Loop to front
	outside3:
	xor	eax,eax		    ;Normal, no error, return value
	ret			    ;Return

Applications in routing

A distributed variant of Bellman-Ford algorithm is used in the Routing Information Protocol (RIP). The algorithm is distributed because it involves a number of nodes (routers) within an Autonomous system, a collection of IP networks typically owned by an ISP. It consists of the following steps:

  1. Each node calculates the distances between itself and all other nodes within the AS and stores this information as a table.
  2. Each node sends its table to all neighbouring nodes.
  3. When a node receives distance tables from its neighbours, it calculates the shortest routes to all other nodes and updates its own table to reflect any changes.

The main disadvantages of Bellman-Ford algorithm in this setting are

  • Does not scale well
  • Changes in network topology are not reflected quickly since updates are spread node-by-node.
  • Counting to infinity

See also: List of algorithms