PageRenderTime 43ms CodeModel.GetById 21ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/3.0/sources/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs

https://github.com/rhishi/QuickGraph
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}