/3.0/sources/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs
C# | 248 lines | 146 code | 25 blank | 77 comment | 16 complexity | 3e1b7239aaba7bbc3e71412ba8cdb688 MD5 | raw file
1using System;
2using System.Collections.Generic;
3using QuickGraph.Algorithms.Services;
4
5namespace QuickGraph.Algorithms.ShortestPath
6{
7 /// <summary>
8 /// Bellman Ford shortest path algorithm.
9 /// </summary>
10 /// <remarks>
11 /// <para>
12 /// The Bellman-Ford algorithm solves the single-source shortest paths
13 /// problem for a graph with both positive and negative edge weights.
14 /// </para>
15 /// <para>
16 /// If you only need to solve the shortest paths problem for positive
17 /// edge weights, Dijkstra's algorithm provides a more efficient
18 /// alternative.
19 /// </para>
20 /// <para>
21 /// If all the edge weights are all equal to one then breadth-first search
22 /// provides an even more efficient alternative.
23 /// </para>
24 /// </remarks>
25 /// <reference-ref
26 /// idref="shi03datastructures"
27 /// />
28 public sealed class BellmanFordShortestPathAlgorithm<TVertex, TEdge>
29 : ShortestPathAlgorithmBase<TVertex,TEdge
30 , IVertexAndEdgeListGraph<TVertex,TEdge>>
31 , ITreeBuilderAlgorithm<TVertex, TEdge>
32 where TEdge : IEdge<TVertex>
33 {
34 private readonly Dictionary<TVertex,TVertex> predecessors;
35 private bool foundNegativeCycle;
36
37 public BellmanFordShortestPathAlgorithm(
38 IVertexAndEdgeListGraph<TVertex, TEdge> visitedGraph,
39 Func<TEdge, double> weights
40 )
41 : this(visitedGraph, weights, DistanceRelaxers.ShortestDistance)
42 { }
43
44 public BellmanFordShortestPathAlgorithm(
45 IVertexAndEdgeListGraph<TVertex, TEdge> visitedGraph,
46 Func<TEdge, double> weights,
47 IDistanceRelaxer distanceRelaxer
48 )
49 : this(null, visitedGraph, weights, distanceRelaxer)
50 { }
51
52 public BellmanFordShortestPathAlgorithm(
53 IAlgorithmComponent host,
54 IVertexAndEdgeListGraph<TVertex,TEdge> visitedGraph,
55 Func<TEdge,double> weights,
56 IDistanceRelaxer distanceRelaxer
57 )
58 :base(host, visitedGraph, weights, distanceRelaxer)
59 {
60 this.predecessors = new Dictionary<TVertex,TVertex>();
61 }
62
63 public bool FoundNegativeCycle
64 {
65 get { return this.foundNegativeCycle;}
66 }
67
68 /// <summary>
69 /// Invoked on each vertex in the graph before the start of the
70 /// algorithm.
71 /// </summary>
72 public event VertexAction<TVertex> InitializeVertex;
73
74 /// <summary>
75 /// Raises the <see cref="InitializeVertex"/> event.
76 /// </summary>
77 /// <param name="v">vertex that raised the event</param>
78 private void OnInitializeVertex(TVertex v)
79 {
80 var eh = this.InitializeVertex;
81 if (eh != null)
82 eh(v);
83 }
84
85 /// <summary>
86 /// Invoked on every edge in the graph |V| times.
87 /// </summary>
88 public event EdgeAction<TVertex,TEdge> ExamineEdge;
89
90 /// <summary>
91 /// Raises the <see cref="ExamineEdge"/> event.
92 /// </summary>
93 /// <param name="e">edge that raised the event</param>
94 private void OnExamineEdge(TEdge e)
95 {
96 var eh = this.ExamineEdge;
97 if (eh != null)
98 eh(e);
99 }
100
101 /// <summary>
102 /// Invoked if the distance label for the target vertex is not
103 /// decreased.
104 /// </summary>
105 public event EdgeAction<TVertex,TEdge> EdgeNotRelaxed;
106
107 /// <summary>
108 /// Raises the <see cref="EdgeNotRelaxed"/> event.
109 /// </summary>
110 /// <param name="e">edge that raised the event</param>
111 private void OnEdgeNotRelaxed(TEdge e)
112 {
113 var eh = this.EdgeNotRelaxed;
114 if (eh != null)
115 eh(e);
116 }
117
118 /// <summary>
119 /// Invoked during the second stage of the algorithm,
120 /// during the test of whether each edge was minimized.
121 ///
122 /// If the edge is minimized then this function is invoked.
123 /// </summary>
124 public event EdgeAction<TVertex,TEdge> EdgeMinimized;
125
126
127 /// <summary>
128 /// Raises the <see cref="EdgeMinimized"/> event.
129 /// </summary>
130 /// <param name="e">edge that raised the event</param>
131 private void OnEdgeMinimized(TEdge e)
132 {
133 var eh = this.EdgeMinimized;
134 if (eh != null)
135 eh(e);
136 }
137
138 /// <summary>
139 /// Invoked during the second stage of the algorithm,
140 /// during the test of whether each edge was minimized.
141 ///
142 /// If the edge was not minimized, this function is invoked.
143 /// This happens when there is a negative cycle in the graph.
144 /// </summary>
145 public event EdgeAction<TVertex,TEdge> EdgeNotMinimized;
146
147
148 /// <summary>
149 /// Raises the <see cref="EdgeNotMinimized"/> event.
150 /// </summary>
151 /// <param name="e">edge that raised the event</param>
152 private void OnEdgeNotMinimized(TEdge e)
153 {
154 var eh = this.EdgeNotMinimized;
155 if (eh != null)
156 eh(e);
157 }
158
159 /// <summary>
160 /// Constructed predecessor map
161 /// </summary>
162 public IDictionary<TVertex,TVertex> Predecessors
163 {
164 get
165 {
166 return predecessors;
167 }
168 }
169
170 protected override void Initialize()
171 {
172 base.Initialize();
173
174 this.foundNegativeCycle = false;
175 // init color, distance
176 this.VertexColors.Clear();
177 foreach (var u in VisitedGraph.Vertices)
178 {
179 this.VertexColors[u] = GraphColor.White;
180 this.Distances[u] = double.PositiveInfinity;
181 this.OnInitializeVertex(u);
182 }
183
184 TVertex root;
185 if (!this.TryGetRootVertex(out root))
186 foreach (var v in this.VisitedGraph.Vertices)
187 {
188 root = v;
189 break;
190 }
191
192 this.Distances[root] = 0;
193 }
194
195 /// <summary>
196 /// Applies the Bellman Ford algorithm
197 /// </summary>
198 /// <remarks>
199 /// Does not initialize the predecessor and distance map.
200 /// </remarks>
201 /// <returns>true if successful, false if there was a negative cycle.</returns>
202 protected override void InternalCompute()
203 {
204 // getting the number of
205 int N = this.VisitedGraph.VertexCount;
206 for (int k = 0; k < N; ++k)
207 {
208 bool atLeastOneTreeEdge = false;
209 foreach (var e in this.VisitedGraph.Edges)
210 {
211 this.OnExamineEdge(e);
212
213 if (Relax(e))
214 {
215 atLeastOneTreeEdge = true;
216 OnTreeEdge(e);
217 }
218 else
219 this.OnEdgeNotRelaxed(e);
220 }
221 if (!atLeastOneTreeEdge)
222 break;
223 }
224
225 var relaxer = this.DistanceRelaxer;
226 foreach (var e in this.VisitedGraph.Edges)
227 {
228 var edgeWeight = Weights(e);
229 if (edgeWeight < 0)
230 throw new InvalidOperationException("non negative edge weight");
231 if (relaxer.Compare(
232 relaxer.Combine(
233 this.Distances[e.Source], edgeWeight),
234 this.Distances[e.Target]
235 ) < 0
236 )
237 {
238 this.OnEdgeMinimized(e);
239 this.foundNegativeCycle = true;
240 return;
241 }
242 else
243 this.OnEdgeNotMinimized(e);
244 }
245 this.foundNegativeCycle = false;
246 }
247 }
248}