1+ using  System ; 
2+ using  System . Diagnostics ; 
3+ using  System . Collections . Generic ; 
4+ using  Algorithms . Common ; 
5+ using  DataStructures . Graphs ; 
6+ 
7+ namespace  Algorithms . Graphs 
8+ { 
9+  public  class  BellmanFordShortestPaths < TGraph ,  TVertex > 
10+  where  TGraph  :  IGraph < TVertex > ,  IWeightedGraph < TVertex > 
11+  where  TVertex  :  IComparable < TVertex > 
12+  { 
13+  /// INSTANCE VARIABLES 
14+  private  int  _edgesCount ; 
15+  private  int  _verticesCount ; 
16+  private  long [ ]  _distances ; 
17+  private  int [ ]  _predecessors ; 
18+  private  WeightedEdge < TVertex > [ ]  _edgeTo ; 
19+ 
20+  // A dictionary that maps node-values to integer indeces 
21+  private  Dictionary < TVertex ,  int >  _nodesToIndices ; 
22+ 
23+  // A dictionary that maps integer index to node-value 
24+  private  Dictionary < int ,  TVertex >  _indicesToNodes ; 
25+ 
26+  // A const that represent an infinite distance 
27+  private  const  Int64  Infinity  =  Int64 . MaxValue ; 
28+  private  const  int  NilPredecessor  =  - 1 ; 
29+ 
30+ 
31+  /// CONSTRUCTOR 
32+  public  BellmanFordShortestPaths ( TGraph  Graph ,  TVertex  Source ) 
33+  { 
34+  if  ( Graph  ==  null )  { 
35+  throw  new  ArgumentNullException  ( ) ; 
36+  }  else  { 
37+  if  ( ! Graph . HasVertex  ( Source ) ) 
38+  throw  new  ArgumentException  ( "The source vertex doesn't belong to graph." ) ; 
39+ 
40+  // Init 
41+  _initializeDataMembers  ( Graph ) ; 
42+ 
43+  // Traverse the graph 
44+  var  status  =  _bellmanFord  ( Graph ,  Source ) ; 
45+ 
46+  if  ( status  ==  false ) 
47+  throw  new  Exception  ( "Negative-weight cycle detected." ) ; 
48+ 
49+  Debug . Assert  ( _checkOptimalityConditions  ( Graph ,  Source ) ) ; 
50+  } 
51+  } 
52+ 
53+ 
54+  /************************************************************************************************************/ 
55+ 
56+ 
57+  /// The Bellman-Ford Algorithm. 
58+  /// <>True if shortest-path computation is finished with no negative-weight cycles detected; otehrwise, false.</> 
59+  private  bool  _bellmanFord ( TGraph  graph ,  TVertex  source ) 
60+  { 
61+  int  srcIndex  =  _nodesToIndices [ source ] ; 
62+  _distances [ srcIndex ]  =  0 ; 
63+ 
64+  var  edges  =  graph . Edges  as  IEnumerable < WeightedEdge < TVertex > > ; 
65+ 
66+  // First pass 
67+  // Calculate shortest paths and relax all edges. 
68+  for  ( int  i  =  1 ;  i  <  graph . VerticesCount  -  1 ;  ++ i ) 
69+  { 
70+  foreach  ( var  edge  in  edges ) 
71+  { 
72+  int  fromIndex  =  _nodesToIndices [ edge . Source ] ; 
73+  int  toIndex  =  _nodesToIndices [ edge . Destination ] ; 
74+ 
75+  // calculate a new possible weighted path if the edge weight is less than infinity 
76+  var  delta  =  Infinity ; 
77+  if  ( edge . Weight  <  Infinity  &&  ( Infinity  -  edge . Weight )  >  _distances [ fromIndex ] )  // Handles overflow 
78+  delta  =  _distances [ fromIndex ]  +  edge . Weight ; 
79+ 
80+  // Relax the edge 
81+  // if check is true, a shorter path is found from current to adjacent 
82+  if  ( delta  <  _distances [ toIndex ] ) 
83+  { 
84+  _edgeTo [ toIndex ]  =  edge ; 
85+  _distances [ toIndex ]  =  delta ; 
86+  _predecessors [ toIndex ]  =  fromIndex ; 
87+  } 
88+  } 
89+  } 
90+ 
91+  // Second pass 
92+  // Check for negative-weight cycles. 
93+  foreach  ( var  edge  in  edges ) 
94+  { 
95+  int  fromIndex  =  _nodesToIndices [ edge . Source ] ; 
96+  int  toIndex  =  _nodesToIndices [ edge . Destination ] ; 
97+ 
98+  // calculate a new possible weighted path if the edge weight is less than infinity 
99+  var  delta  =  Infinity ; 
100+  if  ( edge . Weight  <  Infinity  &&  ( Infinity  -  edge . Weight )  >  _distances [ fromIndex ] )  // Handles overflow 
101+  delta  =  _distances [ fromIndex ]  +  edge . Weight ; 
102+ 
103+  // if check is true a negative-weight cycle is detected 
104+  // return false; 
105+  if  ( delta  <  _distances [ toIndex ] ) 
106+  return  false ; 
107+  } 
108+ 
109+  // Completed shortest paths computation. 
110+  // No negative edges were detected. 
111+  return  true ; 
112+  } 
113+ 
114+  /// Constructors helper function. Initializes some of the data memebers. 
115+  private  void  _initializeDataMembers ( TGraph  Graph ) 
116+  { 
117+  _edgesCount  =  Graph . EdgesCount ; 
118+  _verticesCount  =  Graph . VerticesCount ; 
119+ 
120+  _distances  =  new  Int64 [ _verticesCount ] ; 
121+  _predecessors  =  new  int [ _verticesCount ] ; 
122+  _edgeTo  =  new  WeightedEdge < TVertex > [ _edgesCount ] ; 
123+ 
124+  _nodesToIndices  =  new  Dictionary < TVertex ,  int > ( ) ; 
125+  _indicesToNodes  =  new  Dictionary < int ,  TVertex > ( ) ; 
126+ 
127+  // Reset the information arrays 
128+  int  i  =  0 ; 
129+  foreach  ( var  node  in  Graph . Vertices ) 
130+  { 
131+  if  ( i  >=  _verticesCount ) 
132+  break ; 
133+ 
134+  _edgeTo [ i ]  =  null ; 
135+  _distances [ i ]  =  Infinity ; 
136+  _predecessors [ i ]  =  NilPredecessor ; 
137+ 
138+  _nodesToIndices . Add ( node ,  i ) ; 
139+  _indicesToNodes . Add ( i ,  node ) ; 
140+ 
141+  ++ i ; 
142+  } 
143+  } 
144+ 
145+  /// Constructors helper function. Checks Optimality Conditions: 
146+  /// (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() 
147+  /// (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() 
148+  private  bool  _checkOptimalityConditions ( TGraph  graph ,  TVertex  source ) 
149+  { 
150+  // Get the source index (to be used with the information arrays). 
151+  int  s  =  _nodesToIndices [ source ] ; 
152+ 
153+  // check that distTo[v] and edgeTo[v] are consistent 
154+  if  ( _distances [ s ]  !=  0  ||  _predecessors [ s ]  !=  NilPredecessor ) 
155+  { 
156+  Console . WriteLine ( "distanceTo[s] and edgeTo[s] are inconsistent" ) ; 
157+  return  false ; 
158+  } 
159+ 
160+  for  ( int  v  =  0 ;  v  <  graph . VerticesCount ;  v ++ ) 
161+  { 
162+  if  ( v  ==  s )  continue ; 
163+ 
164+  if  ( _predecessors [ v ]  ==  NilPredecessor  &&  _distances [ v ]  !=  Infinity ) 
165+  { 
166+  Console . WriteLine ( "distanceTo[] and edgeTo[] are inconsistent for at least one vertex." ) ; 
167+  return  false ; 
168+  } 
169+  } 
170+ 
171+  // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() 
172+  foreach  ( var  vertex  in  graph . Vertices ) 
173+  { 
174+  int  v  =  _nodesToIndices [ vertex ] ; 
175+ 
176+  foreach  ( var  edge  in  graph . NeighboursMap ( vertex ) ) 
177+  { 
178+  int  w  =  _nodesToIndices [ edge . Key ] ; 
179+ 
180+  if  ( _distances [ v ]  +  edge . Value  <  _distances [ w ] ) 
181+  { 
182+  Console . WriteLine ( "edge "  +  vertex  +  "-"  +  edge . Key  +  " is not relaxed" ) ; 
183+  return  false ; 
184+  } 
185+  } 
186+  } 
187+ 
188+  // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() 
189+  foreach  ( var  vertex  in  graph . Vertices ) 
190+  { 
191+  int  w  =  _nodesToIndices [ vertex ] ; 
192+ 
193+  if  ( _edgeTo [ w ]  ==  null ) 
194+  continue ; 
195+ 
196+  var  edge  =  _edgeTo [ w ] ; 
197+  int  v  =  _nodesToIndices [ edge . Source ] ; 
198+ 
199+  if  ( ! vertex . IsEqualTo ( edge . Destination ) ) 
200+  return  false ; 
201+ 
202+  if  ( ( _distances [ v ]  +  edge . Weight )  !=  _distances [ w ] ) 
203+  { 
204+  Console . WriteLine ( "edge "  +  edge . Source  +  "-"  +  edge . Destination  +  " on shortest path not tight" ) ; 
205+  return  false ; 
206+  } 
207+  } 
208+ 
209+  return  true ; 
210+  } 
211+ 
212+ 
213+  /************************************************************************************************************/ 
214+ 
215+ 
216+  /// Determines whether there is a path from the source vertex to this specified vertex. 
217+  public  bool  HasPathTo ( TVertex  destination ) 
218+  { 
219+  if  ( ! _nodesToIndices . ContainsKey ( destination ) ) 
220+  throw  new  Exception ( "Graph doesn't have the specified vertex." ) ; 
221+ 
222+  int  index  =  _nodesToIndices [ destination ] ; 
223+  return  _distances [ index ]  !=  Infinity ; 
224+  } 
225+ 
226+  /// Returns the distance between the source vertex and the specified vertex. 
227+  public  long  DistanceTo ( TVertex  destination ) 
228+  { 
229+  if  ( ! _nodesToIndices . ContainsKey ( destination ) ) 
230+  throw  new  Exception ( "Graph doesn't have the specified vertex." ) ; 
231+ 
232+  int  index  =  _nodesToIndices [ destination ] ; 
233+  return  _distances [ index ] ; 
234+  } 
235+ 
236+  /// Returns an enumerable collection of nodes that specify the shortest path from the source vertex to the destination vertex. 
237+  public  IEnumerable < TVertex >  ShortestPathTo ( TVertex  destination ) 
238+  { 
239+  if  ( ! _nodesToIndices . ContainsKey ( destination ) ) 
240+  throw  new  Exception ( "Graph doesn't have the specified vertex." ) ; 
241+  if  ( ! HasPathTo ( destination ) ) 
242+  return  null ; 
243+ 
244+  int  dstIndex  =  _nodesToIndices [ destination ] ; 
245+  var  stack  =  new  DataStructures . Lists . Stack < TVertex > ( ) ; 
246+ 
247+  int  index ; 
248+  for  ( index  =  dstIndex ;  _distances [ index ]  !=  0 ;  index  =  _predecessors [ index ] ) 
249+  stack . Push ( _indicesToNodes [ index ] ) ; 
250+ 
251+  // Push the source vertex 
252+  stack . Push ( _indicesToNodes [ index ] ) ; 
253+ 
254+  return  stack ; 
255+  } 
256+ 
257+  } 
258+ 
259+ } 
0 commit comments