#### /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
``````  1﻿using 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    {
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}
``````